[TOC]
include/linux/security.h
1 | /** |
security/commoncap.c
cap_capable: 跨用户命名空间的能力检查机制
本代码片段是 Linux 内核安全子系统的基石之一,提供了核心函数 cap_capable
,用于精确地判断一个进程(由其凭证 cred
代表)是否拥有某个特定的能力(Capability),并且这个判断过程完全支持并正确处理了复杂的用户命名空间(User Namespace)层次结构。当内核的其他部分需要进行权限检查时(例如,判断一个进程是否可以重启系统),它们最终都会调用这个函数。
实现原理分析
此机制的核心原理是基于用户命名空间(User Namespace)的层次化能力模型。一个进程的能力不再是一个简单的全局属性,而是与其所属的用户命名空间相关联。cap_capable_helper
函数中的 for(;;)
循环通过向上遍历命名空间树,实现了这一复杂的检查逻辑。
向上遍历(Upward Traversal): 检查的起点是目标资源所属的命名空间
target_ns
。循环通过ns = ns->parent
不断向上移动,直至根命名空间(init_user_ns
)。能力检查的三个关键规则: 在循环的每一层,代码会依次应用以下规则:
- 规则一:同命名空间内的直接检查。
if (likely(ns == cred_ns))
:这是最常见和最高效的情况。如果当前检查的命名空间ns
正是进程凭证所属的命名空间cred_ns
,那么就直接检查该进程的有效能力集(cred->cap_effective
)中是否包含所需的能力位。这是通过位掩码操作cap_raised
实现的。 - 规则二:命名空间所有者特权。
if ((ns->parent == cred_ns) && uid_eq(ns->owner, cred->euid))
:这是用户命名空间的一个核心特性。一个用户在一个父命名空间中创建了一个新的子命名空间,那么该用户(ns->owner
)在这个新的子命名空间内自动获得全部能力。此规则检查的就是这种情况:如果当前检查的命名空间ns
的父命名空间正好是进程所在的命名空间,并且该进程的有效用户ID(cred->euid
)与ns
的所有者ID 匹配,那么就授予权限。 - 规则三:父命名空间能力继承。循环本身
ns = ns->parent
体现了继承原则。如果一个进程在某个父命名空间中拥有某项能力,那么它自动对该父命名空间下的所有子孙命名空间都拥有该项能力。循环会持续向上,直到在某个父命名空间中通过了规则一的直接检查。
- 规则一:同命名空间内的直接检查。
提前终止优化:
if (ns->level <= cred_ns->level)
检查是一个重要的优化。level
代表命名空间的嵌套深度。如果向上遍历的过程中,ns
的深度已经小于或等于进程凭证cred_ns
的深度,但ns
却不等于cred_ns
,这说明它们处于不同的分支, 沿着这条路继续前进是没有意义的。
代码分析
1 | /** |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 wdfk-prog的个人博客!
评论