您的位置:首页 > 移动开发 > Android开发

安全策略的生成----SEAndroid in Android 5.x

2015-12-09 16:08 351 查看
android系统中第一个启动的进程是init进程,这个进程会执行系统初始化,其中就包括加载SEAndroid安全策略,查看文件system/core/init/init.c的main函数,其中有:

 
unionselinux_callback cb;
cb.func_log= log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);

cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);

selinux_initialize();


      这里调用了两个与SEAndroid相关的函数:

1.selinux_set_callback,用来向libselinux设置SEAndroid日志和审计回调函数。该函数的实现在external/libselinux/src/callbacks.c文件中:
void
selinux_set_callback(int type, union selinux_callback cb)
{
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;
}
}


2.selinux_initialize(),查看这个函数的实现:
static void selinux_initialize(void)
{
if(selinux_is_disabled()) {
return;
}

INFO("loading selinux policy\n");
if(selinux_android_load_policy()< 0){
ERROR("SELinux: Failed to load policy; rebooting into recoverymode\n");
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
while (1) { pause(); }  // never reached
}

selinux_init_all_handles();
boolis_enforcing = selinux_is_enforcing();
INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
security_setenforce(is_enforcing);
}


       查看该函数调用到的其他函数:
selinux_init_all_handles(),这个函数在system/core/init/init.c文件中,它通过调用libselinux的函数来打开前面分析file_contexts和property_contexts文件,以便可以用来查询系统文件和系统属性的安全上下文。 
void selinux_init_all_handles(void)
{
sehandle =selinux_android_file_context_handle();
selinux_android_set_sehandle(sehandle);
sehandle_prop = selinux_android_prop_context_handle();
}


selinux_android_load_policy,这个函数用来加载安全策略到内核空间的SELinuxLSM模块中,实现在external/libselinux/android.c中,查看这个函数的实现,并且将其中的常量的值标注出来(常量值定义在external/libselinx/src/policy.h中):
int selinux_android_load_policy(void)
{
const char*mnt = SELINUXMNT;  //"/sys/fs/selinux"
intrc;
rc =mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); //"selinuxfs"
if (rc <0) {
if (errno ==ENODEV) {

return-1;
}
if (errno ==ENOENT) {

mnt =OLDSELINUXMNT;  //"/selinux"
rc =mkdir(mnt, 0755);
if (rc == -1&& errno != EEXIST) {
selinux_log(SELINUX_ERROR,"SELinux:  Could notmkdir:  %s\n",
strerror(errno));
return-1;
}
rc =mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
}
}
if (rc <0) {
selinux_log(SELINUX_ERROR,"SELinux:  Could notmount selinuxfs:  %s\n",
strerror(errno));
return-1;
}
set_selinuxmnt(mnt);

returnselinux_android_load_policy_helper(false);
}


      这个函数首先尝试以/sys/fs/selinux为安装点,安装SELinux文件系统,来和内核的LSM模块通信,如果失败,则将安装点改为/selinux。

      安装系统安装完毕后,调用selinux_android_load_policy_helper()函数,将安全策略写入到LSM模块中。查看这个函数的实现:
static int selinux_android_load_policy_helper(bool reload)
{
int fd = -1,rc;
struct statsb;
void *map =NULL;

if (reload&& !selinux_android_use_data_policy())
return0;

fd =open(sepolicy_file[policy_index], O_RDONLY |O_NOFOLLOW);
if (fd <0) {
selinux_log(SELINUX_ERROR, "SELinux:  Could notopen sepolicy:  %s\n",
strerror(errno));
return-1;
}
if(fstat(fd, &sb) < 0) {
selinux_log(SELINUX_ERROR, "SELinux:  Could notstat %s:  %s\n",
sepolicy_file[policy_index], strerror(errno));
close(fd);
return-1;
}
map =mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map ==MAP_FAILED) {
selinux_log(SELINUX_ERROR, "SELinux:  Could notmap %s:  %s\n",
sepolicy_file[policy_index], strerror(errno));
close(fd);
return-1;
}

rc =security_load_policy(map, sb.st_size);
if (rc <0) {
selinux_log(SELINUX_ERROR, "SELinux:  Could notload policy:  %s\n",
strerror(errno));
munmap(map,sb.st_size);
close(fd);
return-1;
}

munmap(map,sb.st_size);
close(fd);
selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n",sepolicy_file[policy_index]);

return0;
}


       函数open(sepolicy_file[policy_index], O_RDONLY |O_NOFOLLOW)的作用是查找sepolicy文件。按照sepolicy_file的定义:
static const char *const sepolicy_file[] = {
"/sepolicy",
"/data/security/current/sepolicy",
NULL};


函数会按照这个顺序查找sepolicy文件(在当前运行的版本中,该sepolicy文件在/sepolicy)。如果找不到,或者版本错误或disabled,则报错。如果找到,将文件的内容映射到内存当中,起始地址是map。然后,调用security_load_policy函数。这个函数的实现在external/libselinux/src/load_policy.c中:

 
int security_load_policy(void *data, size_tlen)
{
char path[PATH_MAX];
int fd, ret;

if (!selinux_mnt) {
errno = ENOENT;
return -1;
}

snprintf(path, sizeof path, "%s/load", selinux_mnt);
fd = open(path, O_RDWR);
if (fd < 0)
return -1;

ret = write(fd, data, len);
close(fd);
if (ret < 0)
return -1;
return 0;
}


     selinux_mnt是一个全局变量,是SELinux文件系统的安装点。在当前系统中,它的值就等于/sys/fs/selinux。函数security_load_policy的实现很简单,它首先打开/sys/fs/selinux/load文件,然后将参数data所描述的安全策略写入到这个文件中去。由于/sys/fs/selinux是由内核空间的SELinuxLSM模块导出来的文件系统接口,因此当我们将安全策略写入到位于该文件系统中的load文件时,就相当于是将安全策略从用户空间加载到SELinuxLSM模块中去了。以后SELinux
LSM模块中的Security Server就可以通过它来进行安全检查。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息