3进程安全上下文
前面一篇文章分析了文件安全上下文关联过程。但是在SEAndroid中,除了要给文件关联安全上下文外,
还需要给进程关联安全上下文,因为只有当进程和文件都关联安全上下文之后,SEAndroid安全策略才能发挥作用。
也就是说,当一个进程试图访问一个文件时,SEAndroid会将进程和文件的安全上下文提取出来,根据安全策略规则,决定是否允许访问。
在传统的Linux系统中,每一个应用程序都对应有一个可执行文件。在这种情况下,我们就可以在安全策略中设定一个规则:
当一个可执行文件加载到一个进程中执行时,该进程的安全上下文就设置为指定的值。也就是说,我们可以在安全策略中静态地
为进程设置安全上下文。然而,这种进程安全上下文设置方式不适合于Android系统中的应用程序进程。
同样的,android系统也有不同的进程,在此仅论述android上层的应用进程。
应用程序进程是由ActivityManagerService请求Zygote进程创建的。ActivityManagerService在请求Zygote进程创建
应用程序进程的时候,会传递很多参数,例如应用程序在安装时分配到的uid和gid。增加了SEAndroid安全机制之后,
ActivityManagerService传递给Zygote进程的参数包含了一个seinfo。不过它的作用是用来设置应用程序进程的安全上下文,
而不是设置应用程序数据文件的安全上下文。
当ActivityMangerService需要创建应用程序进程的时候,就会调用startProcessLocked方法,
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
其中就包含了要创建的应用程序进程的各种参数, 这些参数会通过socket传递给Zygote进程。
最后,Zygote进程会通过调用ZygoteConnection类的成员函数runOnce来执行创建应用程序进程的工作。
3.1 Java层创建进程
Zygote进程进行。
ZygoteConnection类的runOnce方法首先是调用readArgumentList方法读取ActivityManagerService发送
过来的应用程序进程创建参数args,接着再创建一个Arguments对象来解析该参数。
解析后得到的参数传递给Zygote类的forkAndSpecialize方法执行创建应用程序进程的工作。
Zygote的forkAndSpecialize方法如下,
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
instructionSet, appDataDir);
com_android_internal_os_Zygote.cpp对应的nativeForkAndSpecialize方法会调用ForkAndSpecializeCommon方法,
ForkAndSpecializeCommon首先创建一个进程,
pid_t pid = fork();
设置pid,uid等信息,
int rc = setresgid(gid, gid, gid);
rc = setresuid(uid, uid, uid);
设置进程安全上下文
if (java_se_info != NULL) {
se_info = new ScopedUtfChars(env, java_se_info);
se_info_c_str = se_info->c_str();
•••
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
如果不设置进程的安全上下文,那么创建出来的子进程的安全上下文继承于Zygote进程,也就是“u:r:zygote:s0”。
3.2 native层设置安全上下文
和文件的安全上下文一样, 设置进程的安全上下文也在libselinux.so库中进行。
android.c的selinux_android_setcontext方法如下,
int selinux_android_setcontext(uid_t uid,
bool isSystemServer,
const char *seinfo,
const char *pkgname)
{
char *orig_ctx_str = NULL, *ctx_str;
context_t ctx = NULL;
int rc = -1;
if (is_selinux_enabled() <= 0) //是否启用了SELinux
return 0;
rc = getcon(&ctx_str); // 获取原来已有的安全上下文
//进程在创建的时候,默认设置的是父进程的安全上下文
if (rc)
goto err;
// 创建一个新的安全上下文ctx,以便可以获得原来安全上下文的SELinux用户、角色和安全级别等信息。
ctx = context_new(ctx_str);
orig_ctx_str = ctx_str;
if (!ctx)
goto oom;
//根据传进来的参数seinfo在seapp_contexts文件中找到对应的Type,
//并且将其设置为新的安全上下文ctx的Type。
rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
if (rc == -1)
goto err;
else if (rc == -2)
goto oom;
//获取新创建的安全上下文的字符串
ctx_str = context_str(ctx);
if (!ctx_str)
goto oom;
//验证新创建的安全上下文的正确性
rc = security_check_context(ctx_str);
if (rc < 0)
goto err;
if (strcmp(ctx_str, orig_ctx_str)) {
// 设置新创建的安全上下文
rc = setcon(ctx_str);
if (rc < 0)
goto err;
}
•••
利用ps -Z指令可以看到进程的安全上下文,
至此,从Java层到native,最后到libselinux.so库,分析完了在SEAndroid安全机制中,进程安全上下文的设置过程了.