最准、最轻量的方式是直接读取/proc/[pid]/status中的Cap*字段并用capsh --decode解码,CapEff为内核权限检查唯一依据,全零表示无生效能力,CapPrm表上限,CapBnd为硬边界,普通用户可读自身进程,结果可靠且不依赖进程运行状态或ptrace限制。

直接看 /proc/[pid]/status 里的 Cap 字段,再用 capsh --decode 解码——这是最准、最轻量的方式,不依赖进程是否还在运行或是否被 ptrace 限制。
查 /proc/[pid]/status 中的 Cap* 字段
Linux 内核把每个进程的五种能力集(CapInh、CapPrm、CapEff、CapBnd、CapAmb)以十六进制位图形式写在 /proc/[pid]/status 里。只要进程没退出,这个文件就可读。
-
CapEff是最关键的:内核做权限检查时只看它,值为0000000000000000意味着当前没启用任何能力 -
CapPrm表示“允许使用的能力上限”,但不等于已生效;如果CapEff全零而CapPrm非零,说明程序没主动启用能力(比如没调cap_set_proc()) -
CapBnd是硬性边界,所有能力都不能超出它;容器环境常被清空部分位(如移除CAP_SYS_ADMIN) - 普通用户也能读自己启动的进程的这些字段,无需 root 权限
命令示例:
cat /proc/1234/status | grep Cap
输出类似:
CapInh: 0000000000000000 CapPrm: 00000000a80425fb CapEff: 00000000a80425fb CapBnd: 0000003fffffffff CapAmb: 0000000000000000
用 capsh --decode 解码十六进制值
capsh --decode 是唯一能准确把位图转成能力名的标准工具,不依赖 libc 或 shell 环境变量,结果可靠。
- 必须传入完整 16 字符(或 32 字符)十六进制字符串,少一位会解错(例如
00000000a80425fb不是a80425fb) - 一个值可能对应多个能力,比如
00000000a80425fb解出来含cap_net_bind_service、cap_kill、cap_sys_ptrace等十多个 - 如果解码后为空,不是没能力,而是该位图全零(
0000000000000000),代表没启用任何能力
示例:
capsh --decode=00000000a80425fb
getpcaps 和 pscap 的适用场景与局限
getpcaps 和 pscap 看起来更“高级”,但实际有明显限制:
-
getpcaps 1234本质也是读/proc/1234/status,再调capsh --decode,多一层封装,出错时反而难定位 -
pscap -a依赖/proc下所有 PID 目录可遍历,某些安全加固系统(如 grsecurity 补丁)会禁止非 root 查看其他用户进程,此时直接报 “Permission denied” - 它们对
CapAmb(环境能力)支持不一致,内核 4.3+ 引入的CapAmb在旧版pscap中可能被忽略
为什么不能只看 getcap?
getcap /path/to/binary 查的是**文件 capability**,不是进程当前持有的能力集:
- 二进制文件设置了
cap_net_bind_service+ep,不代表进程一定拥有它——如果 execve 时被CapBnd过滤掉,或父进程主动 drop 掉了,CapEff就是空的 - 进程可能通过
capset()系统调用动态增删能力,getcap完全看不到这种运行时变化 - 容器中常见情况:镜像里 binary 有 cap,但 runtime(如 runc)默认清空
CapBnd,导致即使 binary 带 cap,进程也拿不到
真正反映“此刻这个进程能干什么”的,只有 /proc/[pid]/status + capsh --decode 这一套组合。其他方法都是间接推断,容易误判。


















