新书上市《深入解析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()函数中会初始化sehandle和sehandle_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() 来设置文件或目录的安全上下文。