LSM框架介绍

LSM是Linux Security Module的简写,是一种安全框架,它定义了很多钩子函数,安插在内核的关键路径上,当执行到这些关键路径时,调用安插的钩子进行安全检查。每个钩子上安装一个函数指针链,当调用钩子时,依次执行挂载在钩子上的函数,为linux实现的不同的安全模块实际上就是在这些钩子上安装函数。

由于钩子时事先定义好的,并且已经安插到了内核的关键路径上,所以开发一个新的安全模块并不会修改内核的其他的部分,由于一个钩子上可以挂在多个函数指针,所以不能的安全模块也是可以共存的,结果就是执行钩子函数时,依次调用安装到钩子上的安全模块函数进行检查。

LSM定义的钩子有:

//所有的钩子都定义在security/security.c文件中
int security_file_open(struct file *file, const struct cred *cred)
  {
      int ret; 
  
      ret = call_int_hook(file_open, 0, file, cred);
      if (ret)
          return ret; 
  
      return fsnotify_perm(file, MAY_OPEN);
  }
  
  int security_task_create(unsigned long clone_flags)
  {
      return call_int_hook(task_create, 0, clone_flags);
  }
  
  void security_task_free(struct task_struct *task)
  {
      call_void_hook(task_free, task);
  }

在内核其他模块需要安全检查的地方调用这些钩子函数进行检查:

  static int do_dentry_open(struct file *f,
                struct inode *inode,
                int (*open)(struct inode *, struct file *),
                const struct cred *cred)
  {
  		...
        error = security_file_open(f, cred);
      if (error)
          goto cleanup_all;
         ...
 }

下面具体来分析钩子函数:

  int security_task_create(unsigned long clone_flags)
  {
      return call_int_hook(task_create, 0, clone_flags);
  }
 // 看看call_int_hook的定义
    #define call_int_hook(FUNC, IRC, ...) ({            \                                                                                                                  
      int RC = IRC;                       \
      do {                            \
          struct security_hook_list *P;           \
                                  \
          list_for_each_entry(P, &security_hook_heads.FUNC, list) { \
              RC = P->hook.FUNC(__VA_ARGS__);     \
              if (RC != 0)                \
                  break;              \
          }                       \
      } while (0);                        \
      RC;                         \
  })

从security_hook_heads.FUNC 头中指向的链表依次取出执行,那么这些链表是怎么生成的呢,可以通过阅读loadpin和yama这两个安全模块来了解,这两个模块非常简单,只有一个文件:

  //loadpin/loadpin.c
    static struct security_hook_list loadpin_hooks[] = { 
      LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
      LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
  };
  
  void __init loadpin_add_hooks(void)
  {
      pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis");
      security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks));
  }
static void loadpin_sb_free_security(struct super_block *mnt_sb)
{
	...
}
static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
{
	...
}
//include/linux/lsm_hooks.h
  #define LSM_HOOK_INIT(HEAD, HOOK) \                                                                                                                                    
      { .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }

  struct security_hook_list {                                                                                                                                            
      struct list_head        list;
      struct list_head        *head;
      union security_list_options hook;
  };
  
struct security_hook_heads security_hook_heads = {
		...
      .sb_free_security =                                                                                                                                                
          LIST_HEAD_INIT(security_hook_heads.sb_free_security),
      .kernel_read_file =                                                                                                                                                
          LIST_HEAD_INIT(security_hook_heads.kernel_read_file),
      ...
}

struct security_hook_heads { 
	...
	struct list_head sb_free_security;
	struct list_head kernel_read_file;
	...
}

  static inline void security_add_hooks(struct security_hook_list *hooks,
                        int count)
  {
      int i;
  
      for (i = 0; i < count; i++) 
          list_add_tail_rcu(&hooks[i].list, hooks[i].head);
  }

以上关于链表的操作我就不过多讲解了,自己安全数据结构的定义画个图就一目了然了。
通过上面的分析可以知道,不同的安全模块理论上来说是可以共存的,即不同的安全模块的函数钩子可以挂在同一个security_hook_heads.head, 这样不同的安全模块将被依次调用。

但是实际上并不是这样的,有些安全模块之间做了一些互斥选择:

static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =                                                                                                             
      CONFIG_DEFAULT_SECURITY;
 //通过配置可默认选择一个
 //也可以通过内核的cmdline指定这次使用哪个
   static int __init choose_lsm(char *str)
  {
      strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
      return 1;
  }
  __setup("security=", choose_lsm);
 
	int __init security_module_enable(const char *module)
  {
      return !strcmp(module, chosen_lsm);                                                                                                                                
  }

安全模块在加载时会检查:
./…/security/smack/smack_lsm.c:4791: if (!security_module_enable(“smack”))
./…/security/tomoyo/tomoyo.c:542: if (!security_module_enable(“tomoyo”))
./…/security/apparmor/lsm.c:871: if (!apparmor_enabled || !security_module_enable(“apparmor”)) {
./…/security/selinux/hooks.c:6460: if (!security_module_enable(“selinux”)) {

因此smack,tomoyo, apparmor,selinux只能同时使用一个,因为它们都是实现了MAC,只是实现的方法不一样罢了,因此没有必要共存,它们和其他的安全模块之间可以共存。

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: lsm6dsrtr是一款高性能、低功耗的6轴惯性测量单元(IMU)芯片,其中包含三轴加速度计和三轴陀螺仪,可以实现准确的运动检测和姿态估计。该芯片通常被应用于物联网、智能穿戴、无人机和智能家居等领域。 为了让lsm6dsrtr能够与处理器进行通信,需要采用相应的驱动程序,其中最常用的是SPI(Serial Peripheral Interface)驱动。SPI驱动是一种同步的、全双工的通信方式,它包括四条线:时钟线、数据输出线、数据输入线和片选线。在SPI通信中,主设备通过片选线控制从设备,实现数据的发送和接收。 在lsm6dsrtr的SPI驱动中,主要包括以下几个步骤: 1. 初始化:初始化SPI总线,并设置lsm6dsrtr芯片的参数; 2. 选择芯片:将片选线置为低电平,选择lsm6dsrtr芯片; 3. 发送命令:向lsm6dsrtr芯片发送读或写命令; 4. 读取数据:读取从lsm6dsrtr芯片返回的数据,并进行相应处理; 5. 关闭片选:将片选线置为高电平,释放lsm6dsrtr芯片。 总的来说,lsm6dsrtr的SPI驱动是一种简单、高效、可靠的通信方式,能够使芯片与处理器相互通信,实现高精度的运动检测和姿态估计。 ### 回答2: LSM6DSRTR是STMicroelectronics推出的一款高性能数字加速度计和陀螺仪器件,采用SPI接口通信。为了实现对该器件的控制和获取数据,需要使用相应的SPI驱动。 首先,需要在SoC的内核中集成SPI驱动程序,并通过设备树文件进行配置。在驱动程序中,需要实现对SPI接口的初始化、传输数据、收取数据等功能。针对LSM6DSRTR的特性,需要设置SPI模式、传输速率、传输位数等参数。在具体编写SPI驱动时,可以参考STMicroelectronics提供的标准代码库。 在传输数据时,需要先向器件写入配置寄存器中的设置值,以确保器件按照该配置进行采样和运算。之后,便可以从器件中读取数据,具体的数据格式可以参考器件的数据手册进行解析和计算。 值得注意的是,由于LSM6DSRTR是一款高性能器件,其数据传输频率较高,因此在编写SPI驱动时需要注意传输稳定性和速率,以保证数据的准确性和完整性。 总之,LSM6DSRTR的SPI驱动程序实现需要充分熟悉SPI接口通信规范与STMicroelectronics的标准代码库,结合器件的数据手册进行设计与开发。 ### 回答3: LSM6DSRTR是一款集成了三轴加速度计和三轴陀螺仪的惯性测量单元(IMU)芯片。它是ST公司推出的高性能MEMS(微电子机械系统)传感器之一,可用于工业、医疗、运动监测等领域。 为了方便与芯片进行通信,需要编写SPI驱动程序。SPI(串行外设接口)是一种常用的通信协议,在LSM6DSRTR中也使用了SPI接口。在编写SPI驱动程序时,需要对SPI总线进行初始化,包括配置时钟源、设置SPI模式(主模式或从模式)、设置数据位宽、设置CPOL和CPHA参数等。 接着,需要编写LSM6DSRTR芯片的寄存器读写函数。LSM6DSRTR芯片内部有很多寄存器,用于存储和控制芯片的状态和数据。在使用SPI通信时,需要通过读写寄存器来配置芯片的工作模式和获取传感器数据。SPI通讯协议中,主机向从机发送指令或数据时,需要指定寄存器地址。因此,读写寄存器的函数需要接收一个寄存器地址参数,并分别实现从LSB和MSB读写两种不同的模式。 最后,需要编写LSM6DSRTR传感器数据获取函数。LSM6DSRTR内置三轴加速度计和陀螺仪,可以实时获取、处理和输出传感器数据。数据获取函数需要向芯片的数据寄存器发送读取请求,并将读到的数据进行处理和转换后输出。 综上所述,编写LSM6DSRTR SPI驱动程序需要实现SPI总线初始化、寄存器读写和传感器数据获取三个主要功能。通过良好的驱动程序,可以实现高效稳定的与LSM6DSRTR芯片的通信,从而实现对传感器数据的快速采集和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值