Linux中capability权能管理的实现
一、内核中Capabilities的详细分析及汇总
1.文件与目录权限相关
#define CAP_CHOWN 0
- 允许修改文件所有者(
chown
)和组所有权(chgrp
),无视_POSIX_CHOWN_RESTRICTED
限制 - 通常仅 root 用户默认拥有此能力
#define CAP_DAC_OVERRIDE 1
- 允许进程完全忽略文件的 DAC 访问限制
#define CAP_DAC_READ_SEARCH 2
- 允许进程忽略文件读及目录搜索的 DAC 访问限制
#define CAP_FOWNER 3
- 允许进程忽略文件属主 ID 必须和进程用户 ID 相匹配的限制
#define CAP_FSETID 4
- 允许在文件所有者变更时保留 S_ISUID/S_ISGID 位(
chown
后不清除) - 允许进程设置文件的所有者 ID 而无需拥有特权
#define CAP_LEASE 28
- 允许进程修改文件锁的 FL_LEASE 标志
- FL_LEASE 标志是文件锁的一种类型,它允许进程在文件上建立租借锁(lease lock)
- 租借锁是一种特殊的文件锁,允许锁的持有者在一定时间内独占对文件的访问权限
#define CAP_LINUX_IMMUTABLE 9
- 允许修改文件的
S_IMMUTABLE
(不可变)和S_APPEND
(仅追加)属性。 - 通常仅 root 用户可设置这些标志
2. 进程与信号相关
#define CAP_KILL 5
- 允许向任意进程发送信号(kill),无视目标进程的用户 ID 匹配限制。
- 默认仅允许进程向同用户或更低权限进程发信号
#define CAP_SETUID 7
- 允许修改进程的 UID(包括
setuid()
、setfsuid()
)。 - 允许在 socket 凭证中伪造 PID
#define CAP_SETGID 6
- 允许修改进程的 GID(包括
setgid()
、setgroups()
) - 允许在 socket 凭证中伪造 GID
#define CAP_SYS_NICE 23
- 允许提升进程优先级(nice 值)、设置实时调度策略(如
SCHED_FIFO
) - 允许修改其他进程(不同 UID)的 CPU 亲和性
3. 网络相关
#define CAP_NET_BIND_SERVICE 10
- 允许绑定到特权端口(<1024)的 TCP/UDP 套接字
#define CAP_NET_BROADCAST 11
- 允许网络广播和多播(如
SO_BROADCAST
套接字选项)
#define CAP_NET_ADMIN 12
- 允许配置网络接口、防火墙、路由表等
- 包括修改 TOS(服务类型)、混杂模式、多播等
#define CAP_NET_RAW 13
- 允许使用 RAW 和 PACKET 套接字(如
socket(AF_PACKET, SOCK_RAW, ...)
) - 可绕过传输层协议(直接访问链路层)
4. IPC 与内存管理
#define CAP_IPC_LOCK 14
- 允许锁定共享内存段(
mlock()
、mlockall()
),防止交换到磁盘
#define CAP_IPC_OWNER 15
- 绕过 IPC 对象(消息队列、信号量、共享内存)的所有权检查
#define CAP_SYS_RESOURCE 24
- 覆盖资源限制(如
ulimit
)、配额限制 - 允许修改 IPC 消息队列大小、实时时钟中断频率等
5. 系统管理与特权操作
#define CAP_SYS_MODULE 16
- 允许加载/卸载内核模块
#define CAP_SYS_RAWIO 17
- 允许直接硬件访问
#define CAP_SYS_CHROOT 18
- 允许使用
chroot()
更改根目录
#define CAP_SYS_PTRACE 19
- 允许
ptrace()
调试任意进程
#define CAP_SYS_PACCT 20
- 允许进程执行进程的 BSD 式审计
- BSD 式审计是一种记录进程活动信息的机制,包括进程的启动时间、执行时间、资源使用情况等
#define CAP_SYS_ADMIN 21
- 广义系统管理权限,包括:
- 挂载/卸载文件系统(
mount()
、umount()
)。 - 修改磁盘配额、交换空间
- 配置磁盘加密
- 其他底层系统操作
- 挂载/卸载文件系统(
#define CAP_SYS_BOOT 22
- 允许调用
reboot()
重启系统
#define CAP_SYS_TIME 25
- 允许修改系统时钟
- 允许配置实时时钟
#define CAP_SYS_TTY_CONFIG 26
- 允许配置 TTY 设备
#define CAP_MKNOD 27
- 允许
mknod()
创建设备文件
6. 特殊能力
#define CAP_SETPCAP 8
- 允许将自身能力集授予其他进程,或移除其他进程的能力
- 用于权限提升或降权
二、capable
检查是否具备指定权能
#define CAP_TO_MASK(x) (1 << (x))
#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag))
int cap_capable (struct task_struct *tsk, int cap)
{/* Derived from include/linux/sched.h:capable. */if (cap_raised(tsk->cap_effective, cap))return 0;return -EPERM;
}int capable(int cap)
{if (security_ops->capable(current, cap)) {/* capability denied */return 0;}/* capability granted */current->flags |= PF_SUPERPRIV;return 1;
}
1. 宏定义和辅助函数
#define CAP_TO_MASK(x) (1 << (x))
#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag))
CAP_TO_MASK(x)
:将权能编号转换为位掩码- 例如:
CAP_CHOWN(0)
→1 << 0
=0x00000001
CAP_DAC_OVERRIDE(1)
→1 << 1
=0x00000002
- 例如:
cap_raised(c, flag)
:检查权能集c
中是否设置了指定的权能flag
- 返回非零值表示有权能,返回0表示没有权能
2. cap_capable() 函数
int cap_capable(struct task_struct *tsk, int cap)
{/* Derived from include/linux/sched.h:capable. */if (cap_raised(tsk->cap_effective, cap))return 0;return -EPERM;
}
tsk
:要检查的目标进程cap
:要检查的权能编号
返回值:
0
:有权能(成功)-EPERM
:没有权能(权限不足)
3. capable() 函数
int capable(int cap)
{if (security_ops->capable(current, cap)) {/* capability denied */return 0;}/* capability granted */current->flags |= PF_SUPERPRIV;return 1;
}
cap
:要检查的权能编号
返回值:
1
:有权能(成功)0
:没有权能(权限不足)
第1步:通过安全模块检查
if (security_ops->capable(current, cap)) {return 0; // 安全模块拒绝
}
security_ops->capable
:调用安全模块的权能检查钩子- 在默认的 capability 安全模块中,这会调用
cap_capable(current, cap)
- 如果安全模块返回非零(通常是
-EPERM
),表示权能被拒绝
第2步:标记特权使用
current->flags |= PF_SUPERPRIV;
return 1;
PF_SUPERPRIV
:在进程标志中标记该进程使用了特权操作- 用于审计和调试目的,记录特权操作的使用
三、sys_capget
系统调用实现
int cap_capget (struct task_struct *target, kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
{/* Derived from kernel/capability.c:sys_capget. */*effective = cap_t (target->cap_effective);*inheritable = cap_t (target->cap_inheritable);*permitted = cap_t (target->cap_permitted);return 0;
}
static inline int security_capget (struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
{return cap_capget (target, effective, inheritable, permitted);
}
typedef struct __user_cap_data_struct {__u32 effective;__u32 permitted;__u32 inheritable;
} __user *cap_user_data_t;
asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
{int ret = 0;pid_t pid;__u32 version;task_t *target;struct __user_cap_data_struct data;if (get_user(version, &header->version))return -EFAULT;if (version != _LINUX_CAPABILITY_VERSION) {if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))return -EFAULT;return -EINVAL;}if (get_user(pid, &header->pid))return -EFAULT;if (pid < 0)return -EINVAL;spin_lock(&task_capability_lock);read_lock(&tasklist_lock);if (pid && pid != current->pid) {target = find_task_by_pid(pid);if (!target) {ret = -ESRCH;goto out;}} elsetarget = current;ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted);out:read_unlock(&tasklist_lock);spin_unlock(&task_capability_lock);if (!ret && copy_to_user(dataptr, &data, sizeof data))return -EFAULT;return ret;
}
1. 核心功能函数
cap_capget()
- 实际的权能获取函数
int cap_capget(struct task_struct *target, kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
{/* Derived from kernel/capability.c:sys_capget. */*effective = cap_t(target->cap_effective); // 获取有效权能集*inheritable = cap_t(target->cap_inheritable); // 获取可继承权能集 *permitted = cap_t(target->cap_permitted); // 获取允许权能集return 0;
}
作用:直接从目标进程的 task_struct
中读取三个权能集合。
2. 安全模块封装
security_capget()
- 安全模块接口
static inline int security_capget(struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
{return cap_capget(target, effective, inheritable, permitted);
}
作用:作为安全模块的钩子函数,在支持LSM(Linux Security Module)时可以被其他安全模块覆盖
3. 用户空间数据结构
cap_user_data_struct - 用户空间权能数据结构
typedef struct __user_cap_data_struct {__u32 effective; // 有效权能位图__u32 permitted; // 允许权能位图 __u32 inheritable; // 可继承权能位图
} __user *cap_user_data_t;
作用:定义用户空间与内核空间传递权能数据的结构。
4. 系统调用主函数
sys_capget()
- 系统调用入口
4.1.第1段:变量声明和初始化
asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
{int ret = 0;pid_t pid;__u32 version;task_t *target;struct __user_cap_data_struct data; // 内核临时存储
分析:
asmlinkage
表示参数通过栈传递,这是系统调用的标准调用约定header
:用户空间传递的权能头结构,包含版本号和目标PIDdataptr
:用户空间用于接收权能数据的缓冲区指针- 在栈上声明
data
结构作为内核临时存储,避免直接操作用户空间内存
4.2.第2段:版本号获取和验证
/* 1. 从用户空间获取版本号 */if (get_user(version, &header->version))return -EFAULT;/* 2. 版本兼容性检查 */if (version != _LINUX_CAPABILITY_VERSION) {if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))return -EFAULT;return -EINVAL; // 版本不匹配}
分析:
get_user()
:安全地从用户空间读取数据,失败返回-EFAULT
- 版本检查确保用户空间和内核使用相同的权能定义,避免语义不一致
- 如果版本不匹配,先更新头结构中的版本号,再返回错误,这样用户空间可以知道正确的版本
4.3.第3段:目标PID获取和验证
/* 3. 获取目标进程PID */if (get_user(pid, &header->pid))return -EFAULT;if (pid < 0)return -EINVAL; // PID不能为负
分析:
- 从用户空间头结构中获取目标进程PID
- PID有效性检查:Linux中PID必须是非负整数
4.4.第4段:锁保护机制
/* 4. 加锁保护 */spin_lock(&task_capability_lock);read_lock(&tasklist_lock);
分析:
task_capability_lock
:自旋锁,保护权能相关的临界区tasklist_lock
:读写锁,保护进程列表的遍历操作
4.5.第5段:目标进程查找
/* 5. 查找目标进程 */if (pid && pid != current->pid) {// 获取其他进程的权能target = find_task_by_pid(pid);if (!target) {ret = -ESRCH; // 进程不存在goto out;}} else {// 获取当前进程的权能target = current;}
- 三种情况处理:
pid == 0
:获取当前进程权能pid == current->pid
:获取当前进程权能pid != current->pid
:获取其他进程权能
find_task_by_pid()
:在内核进程列表中查找指定PID的进程- 如果目标进程不存在,返回
-ESRCH
(No such process)
4.5.第6段:权能获取核心操作
/* 6. 调用安全模块获取权能 */ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted);
分析:
- 调用安全模块钩子函数
security_capget()
- 在支持LSM(Linux Security Module)时钩子函数可以被其他函数覆盖
4.6.第7段:锁释放和清理
out:/* 7. 释放锁 */read_unlock(&tasklist_lock);spin_unlock(&task_capability_lock);
4.7.第8段:结果返回用户空间
/* 8. 将结果拷贝回用户空间 */if (!ret && copy_to_user(dataptr, &data, sizeof data))return -EFAULT;return ret;
}
分析:
- 只有在前面操作成功(
ret == 0
)时才拷贝数据 copy_to_user()
:安全地将内核数据拷贝到用户空间,失败返回-EFAULT
- 最终返回码:
0
:成功-EFAULT
:用户空间内存访问错误-EINVAL
:参数无效-ESRCH
:目标进程不存在- 其他:安全模块返回的错误码
四、security_capset_set
权能设置操作
void cap_capset_set (struct task_struct *target, kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
{target->cap_effective = *effective;target->cap_inheritable = *inheritable;target->cap_permitted = *permitted;
}
static inline void security_capset_set (struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
{cap_capset_set (target, effective, inheritable, permitted);
}
设置目标进程的三个权能集
五、cap_set_pg
设置进程组所有成员权能
static inline void cap_set_pg(int pgrp, kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
{task_t *g, *target;do_each_task_pid(pgrp, PIDTYPE_PGID, g) {target = g;while_each_thread(g, target)security_capset_set(target, effective, inheritable, permitted);} while_each_task_pid(pgrp, PIDTYPE_PGID, g);
}
1.函数原型和参数
static inline void cap_set_pg(int pgrp, kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
参数说明:
pgrp
:进程组IDeffective
:要设置的有效权能集inheritable
:要设置的可继承权能集permitted
:要设置的允许权能集
2.函数实现分析
2.1. 变量声明
task_t *g, *target;
g
:进程组组长进程指针target
:当前正在处理的进程指针
2.2. 外层循环:遍历进程组
do_each_task_pid(pgrp, PIDTYPE_PGID, g) {
作用:
- 根据进程组ID
pgrp
查找该进程组的所有进程 PIDTYPE_PGID
表示按进程组ID查找- 这个循环会遍历进程组中的每个进程
2.3. 内层循环:遍历线程组
while_each_thread(g, target)security_capset_set(target, effective, inheritable, permitted);
作用:
- 对于进程组中的每个进程,遍历其所有线程
target
遍历该线程组的所有线程- 对每个线程调用
security_capset_set()
设置权能
六、cap_set_all
设置所有线程权能
static inline void cap_set_all(kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
{task_t *g, *target;do_each_thread(g, target) {if (target == current || target->pid == 1)continue;security_capset_set(target, effective, inheritable, permitted);} while_each_thread(g, target);
}
1.函数定义
static inline void cap_set_all(kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
为系统中除当前线程(current
)和 init
进程(pid == 1
)外的所有线程设置能力集(Capabilities)
- 参数
effective
:指向kernel_cap_t
的指针,表示要设置的 Effective 能力集(进程实际可用的能力)inheritable
:指向kernel_cap_t
的指针,表示要设置的 Inheritable 能力集(可被子进程继承的能力)permitted
:指向kernel_cap_t
的指针,表示要设置的 Permitted 能力集(进程可拥有的最大能力集合)
2.代码逻辑解析
2.1. 遍历所有线程
task_t *g, *target;
do_each_thread(g, target) { ... } while_each_thread(g, target);
2.2.跳过当前线程和 init
进程
if (target == current || target->pid == 1)continue;
current
:当前正在执行的线程,直接修改其能力集可能导致权限提升或不稳定pid == 1
(init
进程):是系统关键进程,通常需要保持最高权限(如CAP_SYS_ADMIN
),修改其能力集可能影响系统稳定性
七、security_capset_check
权能设置安全检查
#define cap_t(x) (x).cap
#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set))
static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
{kernel_cap_t dest;cap_t(dest) = cap_t(a) | cap_t(b);return dest;
}
int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
{/* Derived from kernel/capability.c:sys_capset. *//* verify restrictions on target's new Inheritable set */if (!cap_issubset (*inheritable,cap_combine (target->cap_inheritable,current->cap_permitted))) {return -EPERM;}/* verify restrictions on target's new Permitted set */if (!cap_issubset (*permitted,cap_combine (target->cap_permitted,current->cap_permitted))) {return -EPERM;}/* verify the _new_Effective_ is a subset of the _new_Permitted_ */if (!cap_issubset (*effective, *permitted)) {return -EPERM;}return 0;
}
static inline int security_capset_check (struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
{return cap_capset_check (target, effective, inheritable, permitted);
}
1. 宏定义与辅助函数
1.1.cap_t(x)
和 cap_issubset(a, set)
#define cap_t(x) (x).cap
#define cap_issubset(a, set) (!(cap_t(a) & ~cap_t(set)))
-
cap_t(x)
提取
kernel_cap_t
结构体中的cap
字段(实际存储能力位掩码的值) -
cap_issubset(a, set)
检查能力集
a
是否在set
的子集!(a & ~set)
~set
:取set
的补集(即set
没有的能力)。a & ~set
:如果结果非零,说明a
包含set
没有的能力,即a
不是set
的子集!
取反,返回1
(是子集)或0
(不是子集)。
1.2.cap_combine(a, b)
static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b) {kernel_cap_t dest;cap_t(dest) = cap_t(a) | cap_t(b);return dest;
}
- 作用:合并两个能力集
a
和b
(按位或操作)
2.cap_capset_check()
int cap_capset_check(struct task_struct *target, kernel_cap_t *effective,kernel_cap_t *inheritable, kernel_cap_t *permitted)
{/* 1. 检查 target 的新 Inheritable 集是否合法 */if (!cap_issubset(*inheritable,cap_combine(target->cap_inheritable,current->cap_permitted))) {return -EPERM;}/* 2. 检查 target 的新 Permitted 集是否合法 */if (!cap_issubset(*permitted,cap_combine(target->cap_permitted,current->cap_permitted))) {return -EPERM;}/* 3. 检查新的 Effective 集是否是新 Permitted 集的子集 */if (!cap_issubset(*effective, *permitted)) {return -EPERM;}return 0; // 所有检查通过
}
2.1.Inheritable 能力集检查
- 规则:
*inheritable
必须是target
原有inheritable
和current
(调用者)的permitted
的并集的子集 - 目的:防止进程将自身没有的能力传递给其他进程的
inheritable
集 - 示例
target->cap_inheritable
={ CAP_KILL }
current->cap_permitted
={ CAP_SYS_ADMIN }
- 则
*inheritable
最多只能是{ CAP_KILL | CAP_SYS_ADMIN }
的子集
2.2.Permitted 能力集检查
- 规则:
*permitted
必须是target
原有permitted
和current
的permitted
的并集的子集。 - 目的:防止进程提升其他进程的
permitted
集(即使调用者有权限,也不能随意扩大目标进程的能力)
2.3.Effective 能力集检查
- 规则:
*effective
必须是*permitted
的子集 - 目的:确保进程不能启用自身没有的能力(即
effective
不能超出permitted
)
3.security_capset_check()
static inline int security_capset_check(struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted)
{return cap_capset_check(target, effective, inheritable, permitted);
}
- 作用:
security_capset_check
是cap_capset_check
的简单封装,为了兼容 LSM(Linux Security Module)框架
4. 安全检查的核心原则
- 权限继承限制
- 进程只能将自身拥有的能力传递给其他进程的
inheritable
集
- 进程只能将自身拥有的能力传递给其他进程的
- Permitted 集限制
- 进程不能随意扩大其他进程的
permitted
集,只能缩小或保持不变(除非调用者有更高权限)
- 进程不能随意扩大其他进程的
- Effective 集限制
- 进程不能启用自身没有的能力(即
effective
必须 ≤permitted
)
- 进程不能启用自身没有的能力(即
八、sys_capset
系统调用实现
asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
{kernel_cap_t inheritable, permitted, effective;__u32 version;task_t *target;int ret;pid_t pid;if (get_user(version, &header->version))return -EFAULT;if (version != _LINUX_CAPABILITY_VERSION) {if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))return -EFAULT;return -EINVAL;}if (get_user(pid, &header->pid))return -EFAULT;if (pid && !capable(CAP_SETPCAP))return -EPERM;if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||copy_from_user(&permitted, &data->permitted, sizeof(permitted)))return -EFAULT;spin_lock(&task_capability_lock);read_lock(&tasklist_lock);if (pid > 0 && pid != current->pid) {target = find_task_by_pid(pid);if (!target) {ret = -ESRCH;goto out;}} elsetarget = current;ret = -EPERM;if (security_capset_check(target, &effective, &inheritable, &permitted))goto out;if (!cap_issubset(inheritable, cap_combine(target->cap_inheritable,current->cap_permitted)))goto out;/* verify restrictions on target's new Permitted set */if (!cap_issubset(permitted, cap_combine(target->cap_permitted,current->cap_permitted)))goto out;/* verify the _new_Effective_ is a subset of the _new_Permitted_ */if (!cap_issubset(effective, permitted))goto out;ret = 0;/* having verified that the proposed changes are legal,we now put them into effect. */if (pid < 0) {if (pid == -1) /* all procs other than current and init */cap_set_all(&effective, &inheritable, &permitted);else /* all procs in process group */cap_set_pg(-pid, &effective, &inheritable, &permitted);} else {security_capset_set(target, &effective, &inheritable, &permitted);}out:read_unlock(&tasklist_lock);spin_unlock(&task_capability_lock);return ret;
}
1.第1段:变量声明和版本检查
asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
{kernel_cap_t inheritable, permitted, effective;__u32 version;task_t *target;int ret;pid_t pid;if (get_user(version, &header->version))return -EFAULT;if (version != _LINUX_CAPABILITY_VERSION) {if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))return -EFAULT;return -EINVAL;}
分析:
- 声明内核空间的权能集变量用于临时存储
- 版本检查确保用户空间和内核使用相同的权能定义
- 如果版本不匹配,更新头结构版本号并返回错误
2.第2段:PID获取和权限检查
if (get_user(pid, &header->pid))return -EFAULT;if (pid && !capable(CAP_SETPCAP))return -EPERM;
分析:
- 获取目标进程PID
- 关键权限检查:
- 如果
pid != 0
(设置其他进程的权能),需要CAP_SETPCAP
权能 - 如果
pid == 0
(设置当前进程权能),不需要特殊权限
- 如果
3.第3段:从用户空间拷贝权能数据
if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||copy_from_user(&permitted, &data->permitted, sizeof(permitted)))return -EFAULT;
分析:
- 安全地将用户空间传递的权能数据拷贝到内核空间
- 三个权能集:有效集、可继承集、允许集
- 任何拷贝失败都返回
-EFAULT
4.第4段:加锁和目标进程查找
spin_lock(&task_capability_lock);read_lock(&tasklist_lock);if (pid > 0 && pid != current->pid) {target = find_task_by_pid(pid);if (!target) {ret = -ESRCH;goto out;}} elsetarget = current;
分析:
- 双重锁保护:自旋锁保护权能操作,读写锁保护进程列表
- 目标进程查找逻辑:
pid > 0 且 pid != current->pid
:查找其他进程- 其他情况:目标为当前进程
- 如果指定PID的进程不存在,返回
-ESRCH
5.第5段:权能设置合法性验证
ret = -EPERM;if (security_capset_check(target, &effective, &inheritable, &permitted))goto out;if (!cap_issubset(inheritable, cap_combine(target->cap_inheritable,current->cap_permitted)))goto out;/* verify restrictions on target's new Permitted set */if (!cap_issubset(permitted, cap_combine(target->cap_permitted,current->cap_permitted)))goto out;/* verify the _new_Effective_ is a subset of the _new_Permitted_ */if (!cap_issubset(effective, permitted))goto out;ret = 0;
5.1. 安全模块检查
security_capset_check(target, &effective, &inheritable, &permitted)
- 调用安全模块进行额外的安全检查
5.2. 可继承集限制检查
!cap_issubset(inheritable, cap_combine(target->cap_inheritable, current->cap_permitted))
规则:新的可继承集 ⊆ (目标原有可继承集 ∪ 当前进程允许集)
- 防止当前进程授予目标进程超出自己权限的可继承权能
5.3. 允许集限制检查
!cap_issubset(permitted, cap_combine(target->cap_permitted, current->cap_permitted))
规则:新的允许集 ⊆ (目标原有允许集 ∪ 当前进程允许集)
- 防止当前进程授予目标进程超出自己权限的允许权能
5.4. 有效集与允许集一致性检查
!cap_issubset(effective, permitted)
规则:新的有效集 ⊆ 新的允许集
- 确保有效权能不会超过允许的权能范围
6.第6段:实际应用权能设置
/* having verified that the proposed changes are legal,we now put them into effect. */if (pid < 0) {if (pid == -1) /* all procs other than current and init */cap_set_all(&effective, &inheritable, &permitted);else /* all procs in process group */cap_set_pg(-pid, &effective, &inheritable, &permitted);} else {security_capset_set(target, &effective, &inheritable, &permitted);}
根据PID值的不同,有三种设置模式:
6.1. pid > 0
:设置单个进程
security_capset_set(target, &effective, &inheritable, &permitted)
6.2. pid == -1
:设置所有进程(除当前进程和init
进程)
cap_set_all(&effective, &inheritable, &permitted)
6.3. pid < -1
:设置整个进程组
cap_set_pg(-pid, &effective, &inheritable, &permitted)
7.第7段:清理和返回
out:read_unlock(&tasklist_lock);spin_unlock(&task_capability_lock);return ret;
}
分析:
- 对称释放锁资源
- 返回操作结果:
0
:成功-EPERM
:权限不足或验证失败-ESRCH
:目标进程不存在-EFAULT
:用户空间内存访问错误-EINVAL
:版本不匹配或参数无效