Android

来源:互联网 发布:淘宝包邮标签怎么设置 编辑:程序博客网 时间:2024/05/29 06:58

这也是n年前的笔记,重新整理一下。


Linux Capability


关于Linux的capability功能,网上已经有很多文档,这里就简单罗列一下,不细讲了。

进程和文件分别有各自的Capability表示方法。


进程的Capability

cap_effective:
当一个进程要进行某个特权操作时,操作系统会检查cap_effective的对应位是否有效,而不再是检查进程的有效UID是否为0.
例如,如果一个进程要设置系统的时钟,Linux的内核就会检查cap_effective的CAP_SYS_TIME位(第25位)是否有效.

cap_permitted:
表示进程能够使用的能力,在cap_permitted中可以包含cap_effective中没有的能力,这些能力是被进程自己临时放弃的,也可以说cap_effective是cap_permitted的一个子集.

cap_inheritable:
表示能够被当前进程执行的程序继承的能力。

cap_bset:
能力边界集通过sysctl命令导出,用户可以在/proc/sys/kernel/cap-bound中看到系统保留的能力。在默认情况下,能力边界集所有的位都是打开的。

cap_inheritable/ cap_permitted/ cap_effective/ cap_bset保存在struct task_struct-> real_cred中。

struct task_struct {   ...    /* process credentials */    /* objective and real subjective task credentials (COW) */    const struct cred __rcu *real_cred;     /* effective (overridable) subjective task    const struct cred __rcu *cred;..}struct cred {    ...    kernel_cap_t    cap_inheritable; /* caps our children can inherit */    kernel_cap_t    cap_permitted;  /* caps we're permitted */    kernel_cap_t    cap_effective;  /* caps we can actually use */    kernel_cap_t    cap_bset;   /* capability bounding set */    ...}

以下系统调用直接操作自己进程的struct task_struct-> real_cred,修改或读取相应的cap成员。

int capget(cap_user_header_t hdrp, cap_user_data_t datap);  int capset(cap_user_header_t hdrp, const cap_user_data_t datap);

可在/proc/PID/status下察看当前capability:

这里写图片描述

在user space,有专门的cap lib供开发使用。有如下的API可设置进程自己的capability:

cap_initcap_set_flagcap_clearcap_set_proc

文件的Capability


可执行文件也拥有三组能力集,对应于进程的三组能力集,分别称为

cap_effective,cap_allowed cap_forced(分别简记为fE,fI,fP)

其中,cap_allowed表示程序运行时可从原进程的cap_inheritable中集成的能力集,cap_forced表示运行文件时必须拥有才能完成其服务的能力集,而cap_effective则表示文件开始运行时可以使用的能力。

使用user space的工具修改或读取可执行文件的capability:

setcap:

setcap cap_chown=eip /bin/chowncap_chown=eip是将chown的能力以cap_effective(e),cap_inheritable(i),cap_permitted(p)三种位图的方式授权给相关的程序文件.用setcap -r /bin/chown可以删除掉文件的能力。

getcap:

getcap /bin/chown                得到/bin/chown = cap_chown+eip

对于支持扩展属性的文件系统,文件的capability在扩展属性xattr中的定义如下:

#define XATTR_SECURITY_PREFIX   "security."#define XATTR_CAPS_SUFFIX "capability"#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX

即扩展属性名是 security.capability。

在Linux层面,提供如下的系统调用访问文件的Cap:
set:

    sys_fsetxattr    sys_lsetxattr    sys_setxattr

以上3者的区别见 SETXATTR(2)

get:

    sys_fgetxattr    sys_lgetxattr    sys_getxattr

Android 实现


Native Service的Cap


下面以Android进程logd和installd为例来看看native service的实现:

u:r:logd:s0                    logd      476   1     /system/bin/logd

由于logd是由init从init.rc启动,所以需要去除一些不必要的权限,只保留自己需要的:
文件System/core/logd/main.cpp:

drop_privs {    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);    capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |=  CAP_TO_MASK(CAP_AUDIT_CONTROL);    capset(&capheader, &capdata[0])}

可见利用capset重置了Capability。


对于进程installd:

u:r:installd:s0                install   201   1     /system/bin/installd

进入installd进程后,做权限降级处理,只设置自己需要的权限:
framework/native/cmds/installed/installed.c:

drop_privileges {   capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);   capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted        |= CAP_TO_MASK(CAP_CHOWN);   capdata[CAP_TO_INDEX(CAP_SETUID)].permitted       |= CAP_TO_MASK(CAP_SETUID);   capdata[CAP_TO_INDEX(CAP_SETGID)].permitted       |= CAP_TO_MASK(CAP_SETGID);   capdata[CAP_TO_INDEX(CAP_FOWNER)].permitted       |= CAP_TO_MASK(CAP_FOWNER);   capset(&capheader, &capdata[0])}

Android进程的Cap


对Android Server进程和Java进程的Cap处理,是由Zygote进程执行的。
framework/base/core/init/com_android_internal_os_zygote.cpp:

创建普通process时(以BT为例):

com_android_internal_os_Zygote_nativeForkAndSpecialize:    jlong capabilities = 0;    if (uid == AID_BLUETOOTH) {        capabilities |= (1LL << CAP_WAKE_ALARM);    }    ...   SetCapabilities(…)    --> capset(&capheader, &capdata[0])

创建systemServer process时,传入所需的permittedCapabilities/effectiveCapabilities:

com_android_internal_os_Zygote_nativeForkSystemServer:forkAndSpecializeCommon{    if (pid == 0) {        SetCapabilities(…)        --> capset(&capheader, &capdata[0])    }}

而所传入的参数如下:
Zygoteinit.cpp:

startSystemServer:long capabilities = posixCapabilitiesAsBits(            OsConstants.CAP_BLOCK_SUSPEND,            OsConstants.CAP_KILL,            OsConstants.CAP_NET_ADMIN,            OsConstants.CAP_NET_BIND_SERVICE,            OsConstants.CAP_NET_BROADCAST,            OsConstants.CAP_NET_RAW,            OsConstants.CAP_SYS_MODULE,            OsConstants.CAP_SYS_NICE,            OsConstants.CAP_SYS_RESOURCE,            OsConstants.CAP_SYS_TIME,            OsConstants.CAP_SYS_TTY_CONFIG        );

即默认systemserver拥有以上所列的特权。

原创粉丝点击