




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、SEAndroid安全机制中的进程安全上下文关联分析前面一篇文章分析了文件安全上下文关联过程。但是在SEAndroid中,除了要给文件关联安全上下文外,还需要给进程关联安全上下文,因为只有当进程和文件都关联安全上下文之后,SEAndroid安全策略才能发挥作用。也就是说,当一个进程试图访问一个文件时,SEAndroid会将进程和文件的安全上下文提取出来,根据安全策略规则,决定是否允许访问。本文就详细分析SEAndroid的进程安全上下文的关联过程。在传统的Linux系统中,每一个应用程序都对应有一个可执行文件。在这种情况下,我们就可以在安全策略中设定一个规则:当一个可执行文件加载到一个进程中执
2、行时,该进程的安全上下文就设置为指定的值。也就是说,我们可以在安全策略中静态地为进程设置安全上下文。然而,这种进程安全上下文设置方式不适合于Android系统中的应用程序进程。从前面和这两篇文章可以知道,Android系统中的应用程序进程都是由Zygote进程fork出来。这些应用程序进程被Zygote进程fork出来之后,不像传统Linux的应用程序进程一样,会通过exec系统调用将对应的可执行文件加载起来执行。这样就会使得Zygote进程及其创建的所有应用程序进程对应的可执行文件均为/system/bin/app_process。由于我们却需要给不同的应用程序设置不同的安全上下文,以便给它
3、们赋予不同的安全权限,因此我们需要在应用程序进程创建出来之后动态地设置它的安全上下文。 根据上面的描述,我们就总结出,在SEAndroid安全机制中,进程的安全上下文设置分为静态和动态两种方式,如图1所示: 接下来,我们就分别描述这两种进程安全上下文设置方式。 1. 为独立进程静态地设置安全上下文 Android系统的第一个进程是init,其它所有的进程都是由init进程直接或者间接fork出来的。我们在前面一篇文章提到,一个新创建的文件的安全上下文在默认情况下来自于其父目录。与此类似,一个新创建的进程的安全上下文在默认情况下来自于其父进程。因此,我们就先看看系统中的第一个进程init的安全上
4、下文是如何设置的。 查看init进程的启动脚本system/core/rootdir/init.rc,可以看到以下的内容:plain view plain copy 在CODE上查看代码片派生到我的代码片on early-init . # Set the security context for the init process. # This should occur before anything else (e.g. ueventd) is started. setcon u:r:init:s0 . 这段脚本的意思是init进程启动之后就马上调用函数setcon将自己的安全上下文设置为“
5、u:r:init:s0”,即将init进程的domain指定为init。 接下来我们再看看init这个domain的定义,在external/sepolicy/init.te文件中:plain view plain copy 在CODE上查看代码片派生到我的代码片# init switches to init domain (via init.rc). type init, domain; permissive init; # init is unconfined. unconfined_domain(init) tmpfs_domain(init) # add a rule to handl
6、e unlabelled mounts allow init unlabeled:filesystem mount; 第一个type语句将domain设置为init的属性,这意味着init是用来描述进程的安全上下文的。 第二个permissive语句指定当domain为init的进程违反SEAndroid安全策略访问资源时,只进行日志输出,而不是拒绝执行。由于这里列出来的内容是来自Android 4.3的,而Android 4.3开启的是Permissive的SEAndroid模式,因此这里会看到这样的一个permissive语句。 第三个unconfined_domain语句是一个宏,定义在
7、external/sepolicy/te_macros文件中,用来指定init是一个不受限制的domain,即它可以访问系统中的大部分资源。它的定义如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# # unconfined_domain(domain) # Allow the specified domain to do anything. # define(unconfined_domain, typeattribute $1 mlstrustedsubject; typeattribute $1 unconfineddomain; ) 第四个t
8、mpfs_domain语句也是定义在external/sepolicy/te_macros文件中的一个宏,用来指定当domain为init的进程在type为tmpfs的目录中创建文件时,将新创建的文件的type设置为init_tmpfs,并且允许domain为init的进程对它们进行读和执行。它的定义如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# # tmpfs_domain(domain) # Define and allow access to a unique type for # this domain when creating tmp
9、fs / shmem / ashmem files. define(tmpfs_domain, type $1_tmpfs, file_type; type_transition $1 tmpfs:file $1_tmpfs; # Map with PROT_EXEC. allow $1 $1_tmpfs:file read execute execmod ; ) 第5个allow语句允许domain为init的进程mount未指定安全上下文的文件系统时,将其安全上下文设置为unlabeled。 上面列出的脚本就指明了init进程的安全上下文,以及它所具有的SEAndroid权限。接下来我们就
10、再来看看负责创建应用程序进程的Zygote进程的安全上下文的设置过程。 Zygote进程是由init进程创建的,它的启动命令定义在文件system/core/rootdir/init.rc中,如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片service zygote /system/bin/app_process -Xzygote /system/bin -zygote -start-system-server class main socket zygote stream 660 root system onrestart write /sys/
11、android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd 这意味着Zygote进程对应的可执行文件为/system/bin/app_process。 通过检查external/sepolicy/file_contexts,我们可以发现文件/system/bin/app_process的安全上下文为“u:object_r:zygote_exec:s0”,如下所示:plain view plain copy 在CODE上查看代
12、码片派生到我的代码片/system/bin/app_process u:object_r:zygote_exec:s0 也就是说,文件/system/bin/app_process的type为zygote_exec。 在external/sepolicy/zygote.te文件中,定义了一个名称为zygote的domain,以及名称为zygote_exec的type,如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# zygote type zygote, domain; type zygote_exec, exec_type, file_type;
13、 permissive zygote; init_daemon_domain(zygote) unconfined_domain(zygote) 第一个type语句将domain设置为zygote的属性,表明zygote是用来描述进程的安全上下文的。 第二个type语句将exec_type和file_type设置为zygote_exec的属性,表明zygote_exec是用来描述可执行文件的安全上下文的。 第三个permissive语句同样是表明当domain为zygote的进程违反SEAndroid安全策略访问资源时,只进行日志输出,而不是拒绝执行。 第四个init_daemon_domai
14、n语句是一个宏,定义在文件external/sepolicy/te_macros中,用来设置zygote这个domain的权限,它的定义如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# # init_daemon_domain(domain) # Set up a transition from init to the daemon domain # upon executing its binary. define(init_daemon_domain, domain_auto_trans(init, $1_exec, $1) tmpfs_dom
15、ain($1) ) 宏init_daemon_domain由另外两个宏tmpfs_domain和domain_auto_trans组成。宏tmpfs_domain的作用在前面已经分析过了,接下来我们重点关注宏domain_auto_trans的定义,也是在文件external/sepolicy/te_macros中,如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# # domain_auto_trans(olddomain, type, newdomain) # Automatically transition from olddomain to
16、newdomain # upon executing a file labeled with type. # define(domain_auto_trans, # Allow the necessary permissions. domain_trans($1,$2,$3) # Make the transition occur by default. type_transition $1 $2:process $3; ) 第二个type_transition语句指定当一个domain为init的进程创建一个子进程执行一个type为zygote_exec的文件时,将该子进程的domain设置
17、为zygote,而不是继承父进程的domain。 第一个domain_trans语句是一个宏,也是定义在external/sepolicy/te_macros中,用来允许进程的domain从init修改为zygote,它的定义如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# # domain_trans(olddomain, type, newdomain) # Allow a transition from olddomain to newdomain # upon executing a file labeled with type. # Th
18、is only allows the transition; it does not # cause it to occur automatically - use domain_auto_trans # if that is what you want. # define(domain_trans, # Old domain may exec the file and transition to the new domain. allow $1 $2:file getattr open read execute ; allow $1 $3:process transition; # New
19、domain is entered by executing the file. allow $3 $2:file entrypoint read execute ; # New domain can send SIGCHLD to its caller. allow $3 $1:process sigchld; # Enable AT_SECURE, i.e. libc secure mode. dontaudit $1 $3:process noatsecure; # XXX dontaudit candidate but requires further study. allow $1
20、$3:process siginh rlimitinh ; ) 其中,最重要的是以下两个allow语句:plain view plain copy 在CODE上查看代码片派生到我的代码片allow $1 $3:process transition; allow $3 $2:file entrypoint read execute ; 第一个allow语句允许domain为init的进程将domain修改为zygote。 第二个allow语句允许type为zygote_exec的可执行文件作为进入zygote这个domain的入口点。 概括来说,在external/sepolicy/zygote
21、.te文件中,通过init_daemon_domain指明了Zygote进程的domain为zygote。我们可以从Zygote进程的创建过程来理解这些安全策略。首先, Zygote进程是由init进程fork出来的。在fork出来的时候,Zygote进程的domain来自于父进程init的domain,即此时Zygote进程的domain为init。接下来,刚刚fork出来的Zygote进程会通过系统接口exec将文件/system/bin/app_process加载进来执行。由于上面提到的allow和type_transition规则的存在,使得文件/system/bin/app_proc
22、ess被exec到刚刚fork出来的Zygote进程的时候,它的domain自动地从init转换为zygote。这样我们就可以给init进程和Zygote进程设置不同的domain,以便可以给它们赋予不同的SEAndroid安全权限。 回到external/sepolicy/zygote.te文件中,最后一个unconfined_domain语句同样是将zygote这个domain设置为一个不受限的domain,以便它可以访问系统中的大部分资源。 这样,我们就以init和Zygote进程的安全上下文设置过程为例,说明了那些对应有不同可执行文件的进程的安全上下文的关联过程了。这些进程的安全上下文
23、的设置方式与传统的Linux系统的应用程序进程的设置方式是一致的。接下来我们就再来分析Android系统的应用程序进程的安全上下文的关联过程。 2. 为应用程序进程设置安全上下文 从前面一篇文章可以知道,应用程序进程是由ActivityManagerService请求Zygote进程创建的。ActivityManagerService在请求Zygote进程创建应用程序进程的时候,会传递很多参数,例如应用程序在安装时分配到的uid和gid。增加了SEAndroid安全机制之后,ActivityManagerService传递给Zygote进程的参数包含了一个seinfo。这个seinfo与我们在
24、前面一文中介绍的seinfo是一样的,不过它的作用是用来设置应用程序进程的安全上下文,而不是设置应用程序数据文件的安全上下文。接下来我们就分析应用程序进程的安全上下文设置过程。 从前面一文的Step 1可以知道,当ActivityMangerService需要创建应用程序进程的时候,就会调用ActivityMangerService类的成员函数startProcessLocked,它的实现如下所示:java view plain copy 在CODE上查看代码片派生到我的代码片public final class ActivityManagerService extends ActivityM
25、anagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback . private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) . try . / Start the process. It will either succeed and return a result containing / the PID of the new process, or else th
26、row a RuntimeException. Process.ProcessStartResult startResult = Process.start(android.app.ActivityThread, cessName, uid, uid, gids, debugFlags, mountExternal, .targetSdkVersion, .seinfo, null); . catch (RuntimeException e) . . 这个函数定义在文件frameworks/base/services/java/com/androi
27、d/server/am/ActivityManagerService.java中。 参数app指向的是一个ProcessRecord对象,用来描述正在创建的应用程序进程。其中,它的成员变量info指向的是一个ApplicationInfo对象。从前面一文可以知道,这个ApplicationInfo对象有一个类型为String的成员变量seinfo,是在应用程序安装的时候通过解析文件mac_permissions.xml获得的。 ActivityManagerService类的成员函数startProcessLocked通过调用Process类的静态成员函数start来创建应用程序进程,其中就包
28、含了要创建的应用程序进程的各种参数。从前面一篇文章可以知道,这些参数会通过Socket IPC传递给Zygote进程。最后,Zygote进程会通过调用ZygoteConnection类的成员函数runOnce来执行创建应用程序进程的工作。 ZygoteConnection类的成员函数runOnce的实现如下所示:java view plain copy 在CODE上查看代码片派生到我的代码片class ZygoteConnection . boolean runOnce() throws ZygoteInit.MethodAndArgsCaller . try args = readArgum
29、entList(); . catch (IOException ex) . . try parsedArgs = new Arguments(args); . pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName); catch (IOException ex) . catch (ErrnoExce
30、ption ex) . catch (IllegalArgumentException ex) . catch (ZygoteSecurityException ex) . . . 这个函数定义在文件frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java中。 ZygoteConnection类的成员函数runOnce首先是通过调用另外一个成员函数readArgumentList读取ActivityManagerService发送过来的应用程序进程创建参数args,接着再创建一个Arguments对象来解析该
31、参数。解析后得到的参数传递给Zygote类的静态成员函数forkAndSpecialize,以便后者可以执行创建应用程序进程的工作。 Zygote类的静态成员函数forkAndSpecialize的实现如下所示:java view plain copy 在CODE上查看代码片派生到我的代码片public class Zygote . public static int forkAndSpecialize(int uid, int gid, int gids, int debugFlags, int rlimits, int mountExternal, String seInfo, Strin
32、g niceName) preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName); postFork(); return pid; native public static int nativeForkAndSpecialize(int uid, int gid, int gids, int debugFlags, int rlimits, int mountExternal, String seInfo, String
33、niceName); . 这个函数定义在文件libcore/dalvik/src/main/java/dalvik/system/Zygote.java中。 Zygote类的静态成员函数forkAndSpecialize的实现很简单,它通过调用另外一个JNI函数nativeForkAndSpecialize来执行创建应用程序进程的工作。 Zygote类的JNI函数nativeForkAndSpecialize的由C+层的函数Dalvik_dalvik_system_Zygote_forkAndSpecialize来实现,如下所示:cpp view plain copy 在CODE上查看代码片派
34、生到我的代码片static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args, JValue* pResult) pid_t pid; pid = forkAndSpecializeCommon(args, false); RETURN_INT(pid); 这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。 注意,Zygote类的JNI函数nativeForkAndSpecialize在调用的过程中,传递进来的参数都被保存在函数Dalvik_dalvik_sy
35、stem_Zygote_forkAndSpecialize的参数args指向的一块内存中。 函数Dalvik_dalvik_system_Zygote_forkAndSpecialize通过调用另外一个函数forkAndSpecializeCommon来执行创建应用程序进程的工作,它的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer) pid_t pid; uid_t uid = (uid_t) args0;
36、 gid_t gid = (gid_t) args1; . char *seInfo = NULL; char *niceName = NULL; if (isSystemServer) . else . StringObject* seInfoObj = (StringObject*)args6; if (seInfoObj) seInfo = dvmCreateCstrFromString(seInfoObj); . StringObject* niceNameObj = (StringObject*)args7; if (niceNmeObj) niceName = dvmCreateC
37、strFromString(niceNameObj); . . . pid = fork(); if (pid = 0) . err = setSELinuxContext(uid, isSystemServer, seInfo, niceName); . . return pid; 这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。 参数isSystemServer表示当前创建的是System Server进程还是应用程序进程。在我们这个场景中,它的值等于false,表示要创建的是应用程序进程。从参数args指向的内存可以获得各种各样的参
38、数,例如uid、gid、seinfo和nice name等。 获得了要创建的进程的各种参数之后,函数forkAndSpecializeCommon就通过系统调用fork创建出了一个子进程。注意,这时候函数forkAndSpecializeCommon是在Zygote进程中执行的。因此,这里创建出来的子进程的安全上下文继承于Zygote进程。从前面的分析可以知道,这个安全上下文为“u:r:zygote:s0”。 如果这时候我们什么也不做的话,那么创建出来的应用程序进程的安全上下文就会一直被设置为“u:r:zygote:s0”,这样会使得应用程序具有Zygote进程一样的SEAndroid安全权限
39、。这是不允许的,因此,接下来需要通过调用函数setSELinuxContext来修改刚刚创建出来的应用程序进程的安全上下文。 函数setSELinuxContext的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片static int setSELinuxContext(uid_t uid, bool isSystemServer, const char *seInfo, const char *niceName) #ifdef HAVE_ANDROID_OS return selinux_android_setcontext(uid, isSyst
40、emServer, seInfo, niceName); #else return 0; #endif 这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。 函数setSELinuxContext的实现很简单,它通过调用libselinux提供的函数selinux_android_setcontext来设置刚刚创建出来的应用程序进程的安全上下文。 函数selinux_android_setcontext的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片int selinux_android_setc
41、ontext(uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname) char *orig_ctx_str = NULL, *ctx_str; context_t ctx = NULL; int rc; if (is_selinux_enabled() = 0) return 0; _selinux_once(once, seapp_context_init); rc = getcon(&ctx_str); . ctx = context_new(ctx_str); orig_ctx_str = ctx_s
42、tr; . rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx); . ctx_str = context_str(ctx); . rc = security_check_context(ctx_str); . if (strcmp(ctx_str, orig_ctx_str) rc = setcon(ctx_str); . rc = 0; out: . return rc; . 这个函数定义在文件external/libselinux/src/android.c中。 参数isSystemServer表示当前创建的是System Server进程还是应用程序进程。在我们这个场景中,它的值等于false,表示要创建的是应用程序进程。从参数
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025至2030年中国玉米胚芽粕数据监测研究报告
- 2025至2030年中国滥用药品测试剂数据监测研究报告
- 社会管理中磁性技术的应用与发展趋势分析
- 药店配送合同范本
- 2025至2030年中国液体染料数据监测研究报告
- 2025至2030年中国汽车车载天线数据监测研究报告
- 班级心理教育的挑战与对策分析
- 仓库管理责任划分协议
- 客栈定金合同范本
- 2025至2030年中国格拉辛硅油纸数据监测研究报告
- MBR系统运行技术手册
- 稻谷品质测定指标及方法
- 小学四年级上册口算题大全800题(口算天天练)
- 医院医保月结算报表
- 中国农业银行资金证明模板
- 教师如何做小课题研究(李海波)
- 航空煤油 MSDS 安全技术说明书
- 孵化场操作规范(1)
- GB38995-2020婴幼儿用奶瓶和奶嘴
- 中职《普通话》课程标准(共7页)
- 修订韦氏记忆量表(WMS-乙式).doc
评论
0/150
提交评论