与6.3节相呼应,下面还是从“判定”“系统调用”“从文件获取能力”三方面分析Linux的能力机制。
1.判定
Linux内核在做特权判断时,判断的是进程凭证中的有效能力集中是否具备所要求的能力。
2.系统调用
能力机制为Linux内核引入了两个新的系统调用:capget和capset,扩展了一个系统调用prctl。
1)capset
上面所列结构有两个成员:version和pid。出现pid似乎表示可以修改任意一个进程的能力。这有些可怕,想想看,有一种进程可以动态修改别的进程的能力。好在Linux内核自2.6.24后修改了语义,进程只能修改自己的能力。所以这里pid的取值只能是0或者当前进程的pid。
version的取值为:
从“0x19980330”这个值看,Linux内核能力机制的开发开始得相当早。
再看cap_user_data_t:
C语言的参数传递不区分指针和数组。这里实际传递的是一个包含两个子成员的数组,因为当前能力的个数超过了32,一个“__u32”类型的变量只能表示32个能力。
在capset系统调用中有四条规则,必须同时满足:
1)新的可继承能力集必须是旧的可继承能力集和旧的限制能力集的合集的子集。解释一下,如果新的可继承能力集是旧的可继承能力集的子集,没有问题。如果新的可继承能力集有旧的可继承能力集没有的能力,那么这部分能力必须是旧的限制能力集的子集。
2)在进程的有效能力集包含cap_setpcap的情况下,新的可继承能力集必须是旧的可继承能力集和旧的允许能力集的合集的子集。换句话说,若有新增,新增必须来自允许能力集。
3)新的允许能力集必须是旧的允许能力集的子集。
4)新的有效能力集必须是新的允许能力集的子集。(www.xing528.com)
上述规则决定了,通过capset不可能增加允许能力集,通过capset有效能力集总是允许能力集的子集。但是,可继承能力集却有可能超出允许能力集和限制能力集,因为可以构造capset调用参数,在减少允许能力集或限制能力集的同时,不变或增加可继承能力集。
(2)capget
capget可以读取任意进程的能力。
(3)prctl
不知读者是否注意到,capget和capset不涉及限制能力集。限制能力集的查看和修改是通过系统调用prctl来实现的。系统调用prctl有多个参数,限制能力集用到了头两个参数:
限制能力集在参数option中扩展了两个值:
(1)PR_CAPSET_READ
arg2表示一个能力集,整数(unsigned long)的每一个比特表示一个能力,如果这个能力集是限制能力集的子集,返回1;否则返回0。
(2)PR_CAPSET_DROP
将arg2代表的能力集从限制能力集中去掉。这个操作要求进程具有cap_setpcap能力。
还好,现在的能力个数没有达到64,否则就不止要用到prctl的头两个参数了。用PR_CAPSET_READ来读取限制能力集显然不如查阅/proc/[pid]/status方便。而PR_CAPSET_ DROP的设计又指出,进程的限制能力集只能越来越小。
3.从文件获取能力
同UNIX基于id的特权机制一样,在Linux基于能力集合的特权机制中,Linux进程也可以通过系统调用execve从被执行的文件处获取能力。下面看execve前后能力的变化公式:
P表示进程在execve前的能力集,P'表示进程在execve后的能力集,F表示文件的能力集。permitted代表允许能力集,inheritable代表可继承能力集,effective代表有效能力集或有效能力位。
进程在execve后的允许能力集有两个来源,一个是进程的可继承能力集和文件的可继承能力集的交集,另一个是文件的允许能力集和进程的限制能力集的交集。由此可推导出进程的允许能力集有可能不是进程的限制能力集的子集。当文件的有效能力位为1,进程在execve后的有效能力集等于其在execve后的允许能力集。进程的可继承能力集和限制能力集保持不变。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。