Init进程设置SELinux的Policy

本文详细介绍了Android系统中Init进程如何初始化SELinux Policy,包括设置回调函数、加载Policy的过程,以及相关函数的实现细节,如selinux_set_callback、selinux_initialize、selinux_android_load_policy等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

新书上市《深入解析Android 5.0系统》

 以下内容节选自本书


Init进程的main()函数有一段代码用来初始化SELinux,如下所示:

int main(......) {

 ......

  //设置SELinux的回调函数

union selinux_callback cb;

cb.func_log = klog_write;                         

selinux_set_callback(SELINUX_CB_LOG,cb);

cb.func_audit = audit_callback;                   

selinux_set_callback(SELINUX_CB_AUDIT,cb);

// 初始化SELinux

selinux_initialize();   

// 恢复下面目录的安全上下文为系统原始设置

restorecon("/dev");

restorecon("/dev/socket");

restorecon("/dev/__properties__");

restorecon_recursive("/sys");

......

}

这里调用的函数selinux_set_callback()的代码位于目录external/libselinux下。我们先看看函数selinux_set_callback()的代码:

voidselinux_set_callback(int type, union selinux_callbackcb)

{

switch(type) {

caseSELINUX_CB_LOG:

    selinux_log = cb.func_log;

    break;

caseSELINUX_CB_AUDIT:

    selinux_audit = cb.func_audit;

    break;

caseSELINUX_CB_VALIDATE:

    selinux_validate = cb.func_validate;

    break;

caseSELINUX_CB_SETENFORCE:

    selinux_netlink_setenforce =cb.func_setenforce;

    break;

caseSELINUX_CB_POLICYLOAD:

    selinux_netlink_policyload =cb.func_policyload;

    break;

}

}

selinux_set_callback()的作用是对一些全局的函数指针赋值,前面Init进程的main()代码中调用函数selinux_set_callback()的结果是将selinux_log的值设置成klog_write,将selinux_audit的值设置成audit_callback,这两个回调函数并没有太多实际的作用。下面再看看selinux_initialize()函数的代码:

staticvoid selinux_initialize(void)

{

   if (selinux_is_disabled()) {

       return;                                 // 如果SELinux没有enable,退出。

   }

if(selinux_android_load_policy() < 0) { //装载并向内核设置Policy

   // 如果装载SELinuxpolicy失败,重启Android

       android_reboot(ANDROID_RB_RESTART2, 0,"recovery");

       while (1) { pause(); } 

   }

   selinux_init_all_handles();             // 装载文件和属性的安全上下文

   bool is_enforcing =selinux_is_enforcing();

   security_setenforce(is_enforcing);

}

selinux_initialize()函数的主要作用是从文件中读取SELinux的配置文件,然后把它设置到内核中,这样SELinux才能开始工作。我们先看看selinux_is_disabled()函数是如何工作的:

staticbool selinux_is_disabled(void)

{

   char tmp[PROP_VALUE_MAX];

   if (access("/sys/fs/selinux", F_OK) != 0){

       return true;  // 如果目录/sys/fs/selinux不可以访问,说明SeLinuxdisable了。

}

   if((property_get("ro.boot.selinux", tmp) !=0)&&(strcmp(tmp, "disabled")== 0)){

       return true;   //如果ro.boot.selinux等于disabled,说明配置中disableSELinux

   }

   return false;

}

selinux_is_disabled()函数先判断目录/sys/fs/selinux是否可以访问,因为这个目录是SELinux的虚拟文件系统所在的目录,不能返回说明SELinuxdisable了。同时还要判断属性ro.boot.selinux是否等于“disabled”,这个属性值表示SELinux的状态。

selinux_android_load_policy()函数代码如下:

intselinux_android_load_policy(void)

{

   char*mnt = SELINUXMNT;           // mnt设置为/sys/fs/selinux

   intrc;

// 挂载文件系统selinuxfs到目录/sys/fs/selinux

   rc =mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); 

   if(rc < 0) {

      if (errno == ENODEV) {

           return -1;               // 如果mount返回的错误是没有设备,返回。

      }

      if (errno == ENOENT) {        // 如果mount返回的错误表示目录不存在

           mnt = OLDSELINUXMNT;     // 则讲mnt设置为/selinux

           rc = mkdir(mnt, 0755);   // 创建目录

           ...... // 错误处理

// 挂载文件系统selinuxfs到目录/selinux

           rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);     }

  }

...... // 错误处理

  set_selinuxmnt(mnt);                   // mnt的值赋给selinux_mnt

  return selinux_android_reload_policy(); //装载SELinux的策略

}

selinux_android_load_policy()函数首先把SELinux的虚拟文件系统selinuxfs挂载到目录/sys/fs/selinux,如果不成功,再尝试挂载到目录/selinux。挂载成功后,调用selinux_android_reload_policy()函数来装载策略,函数代码如下:

intselinux_android_reload_policy(void)

{

   intfd = -1, rc;

  struct stat sb;

   void*map = NULL;

   inti = 0;

  // 打开一个policy文件

  while (fd < 0 && sepolicy_file[i]){

      fd = open(sepolicy_file[i], O_RDONLY |O_NOFOLLOW);

      i++;

  }

......      // 错误处理

   if(fstat(fd, &sb) < 0) {

      ......  // 错误处理

  }

   map= mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);//mmap文件到内存中

  ......      // 错误处理

   rc =security_load_policy(map, sb.st_size); //装载policy

......     // 错误处理

  munmap(map, sb.st_size);

  close(fd);

  return 0;

}

selinux_android_reload_policy()函数首先打开policy文件,然后把它mmap进内存,最后调用函数security_load_policy()policy设置到内核中。policy文件的文件名保存在数组constsepolicy_file中,定义如下:

staticconst char *const sepolicy_file[] = {

       "/data/security/current/sepolicy",

       "/sepolicy",

       0 };

这两个文件找到一个就可以了,通常是根目录下的sepolicy文件。这个文件就是从源码的external/sepolicy目录下的规则文件编译得到的。

最后我们看看security_load_policy()函数的实现:

intsecurity_load_policy(void *data, size_tlen)

{

   charpath[PATH_MAX];

   intfd, ret;

...... // 检查参数

  snprintf(path, sizeof path, "%s/load", selinux_mnt); 

   fd =open(path, O_RDWR);

  ...... // 错误检查

   ret= write(fd, data, len);  //写入文件

  close(fd);

   if(ret < 0) return -1;

  return 0;

}

security_load_policy() 函数很简单,打开 SELinux 虚拟目录(通常是 /sys/fs/selinux )下的“ load ”文件,然后把策略数据写到文件中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值