linux capabilities的核心是精细化权限控制,而非简单赋予root权限;通过bounding set(硬上限)、permitted(许可池)和inheritable(继承开关)三重机制,实现最小必要权限的精准管控。

Linux Capabilities 的核心不是“要不要 root”,而是“哪些能力能进、哪些必须卡死”。进程边界强化的关键,在于用好 Bounding Set(硬上限)、Permitted(许可池)和 Inheritable(继承开关)这三重机制,让权限只在必要时间、必要位置、以最小粒度生效。
从 Bounding Set 开始收死天花板
Bounding Set 是所有能力的最终防线。一旦从中移除某个能力,该进程及其全部子孙进程永远无法获得它——哪怕 setcap 设了、父进程有、甚至切换成 root 也无效。
- 查看当前系统支持的能力列表:
systemd-analyze capability - 全局收紧(推荐用于生产服务器):在内核启动参数中添加
systemd.capability_bounding_set=cap_net_bind_service cap_net_raw,只保留业务真正需要的能力 - 在 systemd service 文件中禁用高危能力:
CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_MODULE CAP_SYS_PTRACE
按需绑定文件能力,不等于自动启用
setcap 是静态授权的起点,但能力必须写入可执行文件的扩展属性才持久。仅设置文件能力,不等于进程一启动就拥有对应权限——它只是为 Permitted 集提供来源之一。
- 允许普通用户绑定 80 端口:
sudo setcap cap_net_bind_service=+ep /usr/local/bin/myserver(e 表示生效,p 表示许可) - 仅允许子进程继承 raw socket 权限,自身不启用:
sudo setcap cap_net_raw=i /usr/local/bin/packet-tool - 验证是否生效:
getcap /usr/local/bin/myserver,输出应含= cap_net_bind_service+ep
用 Inheritable 控制父子进程权限传递
主进程常需初始化特权(如加载配置、绑定端口),但工作子进程只需极小权限。这时靠 Inheritable + 文件自身的 i 位配合,实现精准遗传。
- 主程序启动时带 cap_net_admin+i:
capsh --inh=cap_net_admin -- -c "./master" - 子进程调用的工具(如 ifconfig)本身也需设
cap_net_admin=i,否则 exec 后 Permitted 中不会出现该能力 - 检查运行中进程的实际能力:
cat /proc/<pid>/status | grep Cap</pid>,重点关注 CapInh(Inheritable)、CapPrm(Permitted)、CapEff(Effective)三行十六进制值
运行时动态降权,避免全程持高权
很多服务只需在初始化阶段用某能力(如读密钥、加载模块),之后应立刻清除。持续持有不必要的能力,等于主动扩大攻击面。
- C 程序中调用
cap_get_proc()和cap_set_proc()清除 Effective 位(前提是对应能力已在 Permitted 中) - 命令行快速测试:
capsh --drop=cap_sys_admin -- -c "whoami" - 启动一个带能力的 shell 并立即降权:
capsh --caps="cap_net_raw+eip" -- -c "/bin/bash",随后可在 shell 内执行capsh --drop=cap_net_raw -- -c "ping -c1 127.0.0.1"验证效果











