Linux Capabilities机制将root权限拆分为40多个独立能力,通过permitted(上限)、effective(内核检查唯一依据)和inheritable(exec时继承控制)三集合实现进程级最小权限控制,支持文件绑定(setcap)与运行时动态调整(capsh/capset)。

Linux 进程权限控制不再只是“root 或普通用户”的二选一。Capability 机制把原本捆绑在 UID 0 上的超级权限,拆成 40 多个独立开关,让进程只拿它真正需要的那一小块权限——比如能绑定 80 端口,但不能改系统时间,也不能删 /etc/shadow。
三个能力集合:permitted、effective、inheritable
每个线程(不是整个进程)维护三组位图,共同决定它能做什么:
- Permitted:权限上限。内核强制限制——effective 里有的能力,必须先出现在 permitted 里;程序自己无法凭空添加新能力,只能从文件能力或父进程继承中获得
-
Effective:内核做权限检查时唯一看的地方。哪怕 permitted 里有 CAP_NET_BIND_SERVICE,如果 effective 没开,bind(80) 仍会返回
Permission denied -
Inheritable:只在
execve()启动子程序时起作用。它和被 exec 的可执行文件自身的 inheritable 位取交集,才决定子进程能否拿到该能力。这是父子进程权限隔离的关键
给可执行文件绑定 capability(静态授权)
能力是写在文件扩展属性里的元数据,不是运行时临时加的。常用操作如下:
- 允许普通用户启动服务并绑定 80 端口:
sudo setcap cap_net_bind_service=+ep /usr/local/bin/myserver - 只允许子进程继承、不立即启用(适合主进程提权后派发任务):
sudo setcap cap_net_raw=i /usr/local/bin/packet-tool - 同时设置多个能力:
sudo setcap cap_sys_admin,cap_dac_override=+ep /usr/local/bin/backup-tool - 查看是否生效:
getcap /usr/local/bin/myserver,输出类似/usr/local/bin/myserver = cap_net_bind_service+ep
运行时动态调整能力(最小化持权)
程序启动后,可以主动降权,避免全程以高权限运行:
- C 程序中调用
capget()和capset()修改 effective 位(前提是对应能力已在 permitted 中) - 命令行快速测试:
capsh --drop=cap_sys_admin -- -c "whoami",临时去掉某能力再执行命令 - 启动一个带能力的 shell:
capsh --inh=cap_net_raw --caps="cap_net_raw+eip" -- -c "/bin/bash",此时 bash 线程的 inheritable 和 effective 都含 cap_net_raw
Docker/Podman 容器中的 capability 控制
容器默认已 drop 多数高危 capability,应在此基础上做减法而非加法:
- 禁用全部,再精准添加必要项:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE --cap-add=CHOWN nginx - 同理适用于 Podman:
podman run --cap-drop=ALL --cap-add=SYS_CHROOT alpine chroot /tmp /bin/sh - 绝对避免
--privileged:它等于开放全部 capability + 关闭 cgroup 隔离 + 绕过 seccomp/SELinux,等同于裸跑 root 容器


















