加载中…
个人资料
行者无疆-超越
行者无疆-超越
  • 博客等级:
  • 博客积分:0
  • 博客访问:23,328
  • 关注人气:1
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

Init进程设置SELinux的Policy

(2014-04-24 11:40:25)
标签:

android

seandroid

selinux

安全

it

分类: Android安全

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()的代码:

void selinux_set_callback(int type, union selinux_callback cb)

{

switch (type) {

case SELINUX_CB_LOG:

     selinux_log = cb.func_log;

     break;

case SELINUX_CB_AUDIT:

     selinux_audit = cb.func_audit;

     break;

case SELINUX_CB_VALIDATE:

     selinux_validate = cb.func_validate;

     break;

case SELINUX_CB_SETENFORCE:

     selinux_netlink_setenforce = cb.func_setenforce;

     break;

case SELINUX_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()函数的代码:

static void 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()函数是如何工作的:

static bool 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()函数代码如下:

int selinux_android_load_policy(void)

{

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

   int rc;

// 挂载文件系统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()函数来装载策略,函数代码如下:

int selinux_android_reload_policy(void)

{

   int fd = -1, rc;

   struct stat sb;

   void *map = NULL;

   int i = 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文件的文件名保存在数组const sepolicy_file中,定义如下:

static const char *const sepolicy_file[] = {

        "/data/security/current/sepolicy",

        "/sepolicy",

        0 };

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

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

int security_load_policy(void *data, size_t len)

{

   char path[PATH_MAX];

   int fd, 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”文件,然后把策略数据写到文件中。

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有