Init进程初始化安全上下文

时间:2022-08-29 17:29:07

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

 以下内容节选自本书


selinux_initialize()函数调用selinux_android_load_policy()函数装载并向内核设置了策略文件后,接着调用了selinux_init_all_handles()函数,这个函数用来装载系统中所有文件和属性的安全上下文,下面我们看看这个函数的代码:

voidselinux_init_all_handles(void)

{

   sehandle = selinux_android_file_context_handle();  // 装载所有文件的安全上下文

   sehandle_prop = selinux_android_prop_context_handle();   //装载所有属性的安全上下文

}

selinux_init_all_handles()函数中会初始化sehandlesehandle_prop两个全局变量,它们将包含所有的安全上下文,下面我们以文件系统为例,看看它是如何实现的,函数selinux_android_file_context_handle()的代码如下:

structselabel_handle*selinux_android_file_context_handle(void)

{

    return file_context_open();

}

这里只是调用了file_context_open()方法,代码如下:

staticstruct selabel_handle*file_context_open(void)

{

  struct selabel_handle *h;

   h =get_selabel_handle(seopts);

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

  return h;

}

file_context_open()使用参数seopts调用了get_selabel_handle()函数,seopts是个全局变量,定义如下:

staticconst struct selinux_opt seopts[] = {

{SELABEL_OPT_PATH, "/data/security/current/file_contexts"},

{SELABEL_OPT_PATH, "/file_contexts" },

{ 0, NULL} };

selinux_opt类型的第一项是类型,第二项是根据第一项内容而定,上面数组中保存的是文件file_contexts路径,系统初始化时它在根目录下,以后如果有修改,则会保存在/data/security/current目录中。文件file_contexts中保存的就是系统中所有文件的安全上下文。

下面我们继续分析get_selabel_handle()函数:

staticstruct selabel_handle *get_selabel_handle(const struct selinux_optopts[]) {

  struct selabel_handle *h;

   inti = 0;

   h =NULL;

  while ((h == NULL) && opts[i].value){

      h = selabel_open(SELABEL_CTX_FILE, &opts[i],1);

      i++;

  }

  return h;

}

get_selabel_handle()函数会对数组seopts中的每个文件调用selabel_open()函数,直到返回值不为NULL。实际上就是找到数组中第一个存在的文件并调用selabel_open()函数,注意调用函数时的第一个参数是SELABEL_CTX_FILE,定义为0,第三个参数是1。函数selabel_open()的代码如下:

structselabel_handle *selabel_open(unsigned intbackend,

                const struct selinux_opt *opts, unsignednopts)

{

struct selabel_handle *rec =NULL;

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

rec = (struct selabel_handle*)malloc(sizeof(*rec));

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

memset(rec, 0,sizeof(*rec));

rec->backend = backend;

rec->validating = selabel_is_validate_set(opts,nopts);

if((*initfuncs[backend])(rec, opts, nopts)) {  //调用函数指针指向的函数

    free(rec);

    rec = NULL;

}

out:

return rec;

}

selabel_open()函数调用了initfuncs数组中保存的函数指针,数组定义如下

staticselabel_initfunc initfuncs[] = {

  &selabel_file_init,

  NULL,

  NULL,

  NULL,

  &selabel_property_init,

};

我们前面强调了参数backend的值为0,所以这里调用的将是函数selabel_file_init()。上面的数组中还有一个函数selabel_property_init(),显然装载属性系统的安全上下文时将调用这个函数。

intselabel_file_init(struct selabel_handle *rec, const structselinux_opt *opts,

         unsigned nopts)

{

  struct saved_data *data;

   data= (struct saved_data*)malloc(sizeof(*data));

   if(!data)

      return -1;

  memset(data, 0, sizeof(*data));

  rec->data = data;

  rec->func_close = &closef;

  rec->func_stats = &stats;

  rec->func_lookup = &lookup;

  return init(rec, opts, nopts);

}

selabel_file_init()中创建了一个saved_data结构,这个结构用来保存所有的安全上下文。对文件的解析是在init()函数中完成了,这个函数有点长,只是在一行行的解析文件,我们就不展开分析了。

得到了文件系统和属性系统的安全上下文后有什么用呢?,我们再看看Init进程中main()函数中调用的restorecon()函数的代码:

intrestorecon(const char *pathname)

{

   char *secontext = NULL;

   struct stat sb;

   int i;

if(is_selinux_enabled() <= 0 ||!sehandle)

   return 0;

   if (lstat(pathname, &sb) < 0)

       return -errno;

   if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode)< 0)

       return -errno;

   if (lsetfilecon(pathname, secontext) < 0){

       freecon(secontext);

       return -errno;

   }

   freecon(secontext);

   return 0;

}

restorecon()函数用来设置路径的安全上下文。首先调用selabel_lookup()函数从sehandle中查找文件或目录对应的安全上下文,然后调用lsetfilecon()函数来设置文件或目录的安全上下文。这也就是读取所有文件的安全上下文并保存到sehandle中的用途。下面我们再看看lsetfilecon()函数是如何设置安全上下文的:

intlsetfilecon(const char *path, const security_context_tcontext)

{

    return lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context)+ 1, 0);

}

lsetfilecon()函数实际上是调用系统函数lsetxattr()来设置文件或目录的安全上下文。