这也是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_init
cap_set_flag
cap_clear
cap_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/chown
cap_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拥有以上所列的特权。