1. Capabilities的主要思想在于分割root用户的特权,即将root的特权分割成不同的能力,每种能力代表一定的特权操作。例如:能力 CAP_SYS_MODULE 表示用户能够加载(或卸载)内核模块的特权操作,而 CAP_SETUID 表示用户能够修改进程。
2. 用户身份的特权操作。在 Capbilities 中,系统将根据进程拥有的能力来进行特权操作的访问控制。在Capilities中,只有进程和可执行文件才具有能力,每个进程拥有三组能力集,分别称为 cap_effective, cap_inheritable, cap_permitted,分别简记为 pE pI pP,其中:
(1) cap_permitted 表示进程所拥有的最大能力集;
(2) cap_effective 表示进程当前可用的能力集,可以看做是 cap_permitted 的一个子集;
(3) cap_inheitable 则表示进程可以传递给其子进程的能力集。
系统根据进程的 cap_effective 能力集进行访问控制,cap_effective 为 cap_permitted 的子集,进程可以通过取消 cap_effective 中的某些能力来放弃进程的一些特权。
3. 可执行文件也拥有三组能力集,对应于进程的三组能力集,分别称为 cap_effective, cap_allowed, cap_forced,分别简记为 fE fI fP,其中:
(1) cap_allowed 表示程序运行时可从原进程的 cap_inheritable 中继承的能力集;
(2) cap_forced 表示运行文件时必须拥有才能完成其服务的能力集;
(3) ap_effective 表示文件开始运行时可以使用的能力。
4. Linux内核从2.2版本开始,就加进的 Capabilities 的概念与机制,并随着版本升高逐步得到改进。在linux中,root权限被分割成以下29中能力:
CAP_CHOWN: 修改文件属主的权限
CAP_DAC_OVERRIDE: 忽略文件的DAC访问限制
CAP_DAC_READ_SEARCH: 忽略文件读及目录搜索的DAC访问限制
CAP_FOWNER:忽略文件属主ID必须和进程用户ID相匹配的限制
CAP_FSETID: 允许设置文件的 setuid 位
CAP_KILL: 允许对不属于自己的进程发送信号
CAP_SETGID: 允许改变进程的组ID
CAP_SETUID: 允许改变进程的用户ID
CAP_SETPCAP: 允许向其他进程转移能力以及删除其他进程的能力
CAP_LINUX_IMMUTABLE: 允许修改文件的 IMMUTABLE 和 APPEND 属性标志
CAP_NET_BIND_SERVICE: 允许绑定到小于1024的端口
CAP_NET_BROADCAST: 允许网络广播和多播访问
CAP_NET_ADMIN: 允许执行网络管理任务
CAP_NET_RAW: 允许使用原始套接字
CAP_IPC_LOCK: 允许锁定共享内存片段
CAP_IPC_OWNER: 忽略IPC所有权检查
CAP_SYS_MODULE: 允许插入和删除内核模块
CAP_SYS_RAWIO: 允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备
CAP_SYS_CHROOT: 允许使用chroot()系统调用
CAP_SYS_PTRACE: 允许跟踪任何进程
CAP_SYS_PACCT: 允许执行进程的BSD式审计
CAP_SYS_ADMIN: 允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
CAP_SYS_BOOT: 允许重新启动系统
CAP_SYS_NICE: a.允许提升自己的优先级和设置其他进程的优先级;b.允许设置自己的RT调度策略和将其它线程设置为RT线程;c.允许设置其它线程的cpu亲和性
CAP_SYS_RESOURCE: 忽略资源限制
CAP_SYS_TIME: 允许改变系统时钟
CAP_SYS_TTY_CONFIG: 允许配置TTY设备
CAP_MKNOD: 允许使用 mknod()系统调用
CAP_LEASE: 允许修改文件锁的 FL_LEASE 标志
5. 可以使用 setcap/getcap 命令行工具进行设置这些权限,可以使用 capset 系统调用设置权限。
if (AID_ROOT == getuid()) { LOGI("[%s]setmediaservercapinrootmode,adjustitforthreadRTschedulepolicy",__func__); if(-1 == prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { LOGW("mediaserverprctlforsetcapsfailed:%s",strerror(errno)); } else { __user_cap_header_struct hdr; __user_cap_data_struct data; hdr.version = _LINUX_CAPABILITY_VERSION; //setcaps hdr.pid = getpid(); data.effective = ((1 << CAP_SYS_NICE) | (1 << CAP_SETUID) | (1 << CAP_SETGID)); data.permitted = ((1 << CAP_SYS_NICE) | (1 << CAP_SETUID) | (1 << CAP_SETGID)); data.inheritable = 0xffffffff; if (-1 == capset(&hdr, &data)) { LOGW("mediaservercapsettingfailed,%s",strerror(errno)); } } }
上面代码,把 root 的权限先使用 prctl 进行 keep,然后通过 capset 进行了限制。capset 的限制过程中,将目录访问的权限消除掉了,会导致无法在/data/system下创建文件,做如下修改便可以恢复:
data.effective = ((1 << CAP_SYS_NICE) | (1 << CAP_SETUID) | (1 << CAP_SETGID) | (1<<CAP_DAC_OVERRIDE)); data.permitted = ((1 << CAP_SYS_NICE) | (1 << CAP_SETUID) | (1 << CAP_SETGID) | (1<<CAP_DAC_OVERRIDE));
6. 其它相关命令工具有:chattr lcap
7. sched_setscheduler()的 capability 需求
一般子进程会继承父进程的调度策略,在 Linux 2.6.32 之后,可以使用 SCHED_RESET_ON_FORK 按位与参数的方式调用 sched_setscheduler(), 使用之后效果是:如果调用进程使用 SCHED_FIFO 或 SCHED_RR 调度策略,使用 SCHED_RESET_ON_FORK 后fork创建的子进程创建时将会自动重置为 SCHED_OTHER 调度策略;如果调用进程使用负值nice,那么使用 SCHED_RESET_ON_FORK 后 fork 创建的子进程创建时将会自动将其 nice 重置为0。 这个标记激活时只有当进程具有 CAP_SYS_NICE 标记时才能被重置,而这个 CAP_SYS_NICE 标记在使用fork()创建子进程后,在子进程中被禁止。
参考:
setcap详解:https://www.cnblogs.com/nf01/articles/10418141.html
用capability 特征加强Linux系统安全:https://blog.csdn.net/cuikeng1956/article/details/100400918