新书上市《深入解析Android 5.0系统》
以下内容节选自本书
前面我们已经介绍了客体的安全上下文是通过文件file_contexts来指定的。但是作为主体的进程,它的安全上下文又是在哪里指定的呢?我们知道,启动进程有两种方式,一种是通过init进程来启动守护进程,另一种是通过Zygote来启动应用进程。
在“7.1.2节启动Service进程”中介绍service_star()t函数时有一段代码是关于获得守护进程的安全上下文的,让我们一起来看看:
if(is_selinux_enabled() > 0) {
if (svc->seclabel) { // 如果init.rc中已经指定了安全上下文
scon = strdup(svc->seclabel); // 拷贝一份
...... // 错误处理
} else {
char *mycon = NULL, *fcon = NULL;
rc = getcon(&mycon); // 获得当前进程init的安全上下文
...... // 错误处理
rc = getfilecon(svc->args[0], &fcon); //获得可执行文件的安全上下文
...... // 错误处理
// 计算守护进程的安全上下文
rc = security_compute_create(mycon, fcon,string_to_security_class("process"),
&scon);
freecon(mycon);
freecon(fcon);
...... // 错误处理
}
}
上面的代码中会先检查init.rc中是否已经为守护进程定义了安全上下文,如果定义了,svc的seclabel的值将不会为NULL,它将成为守护进程的安全上下文。如果init.rc中没有定义,则通过调用函数security_compute_create()来计算守护进程的安全上下文。计算使用的参数包括当前进程init的安全上下文已经可执行文件的安全上下文。security_compute_create()函数的代码如下:
intsecurity_compute_create(const security_context_tscon,
const security_context_t tcon,
security_class_t tclass,
security_context_t * newcon)
{
charpath[PATH_MAX];
char*buf;
size_tsize;
int fd,ret;
......
snprintf(path, sizeof path, "%s/create",selinux_mnt);
fd = open(path,O_RDWR); // 打开/sys/fs/selinux/create文件
......
size =selinux_page_size;
buf =malloc(size);
......
// 把init进程的安全上下文和可执行文件的安全上下文拼装在一起
snprintf(buf, size, "%s %s %hu", scon, tcon,unmap_class(tclass));
ret = write(fd,buf, strlen(buf)); // 通过文件create把数据发送到内核
......
memset(buf, 0, size);
ret = read(fd,buf, size - 1); // 从文件create中读回kernel中创建的安全上下文
......
*newcon =strdup(buf); // 拷贝新创建的安全上下文
......// 错误处理
}
security_compute_create()函数原来是通过SELinux虚拟文件系统中的“create”文件来生成守护进程的安全上下文。
得到了安全上下文之后,设置它就很简单了, service_start() 函数中会调用 setexeccon() 函数来设置执行 exec 后进程的安全上下文。