Capabilities

目录

  1. 概述:从 root 全能到精细权限
  2. 历史背景:为什么需要 Capabilities
  3. 完整能力列表与分类
  4. 五大能力集详解
  5. 文件能力(File Capabilities)
  6. 能力继承规则:execve() 时的完整变换
  7. Securebits:纯能力环境
  8. 用户命名空间与 Capabilities
  9. 实战命令大全
  10. Docker 容器与 Capabilities
  11. Capabilities 与 SUID 的对比
  12. 安全加固最佳实践
  13. Capabilities 提权攻击与防范
  14. 总结

1. 概述:从 root 全能到精细权限

在传统的 Unix/Linux 系统中,权限模型是二元的:要么你是 root(UID 0),拥有所有权限;要么你是普通用户,几乎没有特权。这种"全有或全无"的模式存在严重的安全隐患——一个只需要绑定 80 端口的 Web 服务器,却不得不以 root 身份运行,获得了修改系统时间、加载内核模块等它根本不需要的权限。

Linux Capabilities 解决了这个问题。它将 root 的全部特权拆分为 40+ 个独立的能力单元,每个能力代表一组相关的特权操作。进程可以被授予恰好完成工作所需的能力,而不需要完整的 root 权限。

核心概念

传统模型:
  root (UID=0) ─── 拥有所有特权 ─── 可执行任何操作
  普通用户       ─── 无特权       ─── 只能操作自己的资源

Capabilities 模型:
  进程 A ─── CAP_NET_BIND_SERVICE ─── 可绑定 80 端口
  进程 B ─── CAP_SYS_TIME          ─── 可修改系统时钟
  进程 C ─── CAP_DAC_OVERRIDE      ─── 可绕过文件权限
  进程 D ─── (无能力)              ─── 普通进程

Capabilities 在整个安全体系中的位置

应用请求操作
      │
      ▼
┌─────────────────┐
│  1. DAC 检查    │  ← 传统文件权限 (rwx)
│   (UID/GID)     │
└────────┬────────┘
         │ 通过
         ▼
┌─────────────────┐
│  2. SELinux/     │  ← MAC 强制访问控制
│     AppArmor     │
└────────┬────────┘
         │ 通过
         ▼
┌─────────────────┐
│  3. Capabilities │  ← 能力检查
│     (特权操作)   │     这是本文的主题
└────────┬────────┘
         │ 通过
         ▼
     执行操作

2. 历史背景:为什么需要 Capabilities

时间 里程碑
1997 POSIX 1003.1e 草案定义 Capabilities 标准
1999 Linux 2.2:Capabilities 首次引入内核
2003 Linux 2.6.0:Capabilities 机制成熟
2008 Linux 2.6.24:文件能力(File Capabilities)支持,替代 SUID
2008 Linux 2.6.25:Bounding Set 从系统级变为每线程属性
2015 Linux 4.3:Ambient Set 引入,解决非 root 继承问题
2019 Linux 5.0+:用户命名空间 + Capabilities 深度整合
2020 Linux 5.8:CAP_BPF、CAP_PERFMON 从 CAP_SYS_ADMIN 拆分
2021 Linux 5.12:CAP_CHECKPOINT_RESTORE 独立
2024+ 容器生态全面依赖 Capabilities 实现无 root 运行

SUID 的缺陷 → Capabilities 的优势

SUID 问题示例:
  $ ls -l /usr/bin/ping
  -rwsr-xr-x 1 root root /usr/bin/ping
           ↑
       SUID 位:ping 以 root 身份运行

  ping 只需要 CAP_NET_RAW(创建原始套接字),
  但 SUID 却赋予了完整的 root 权限!
  如果 ping 存在缓冲区溢出漏洞,攻击者获得 root shell。

Capabilities 方案:
  $ sudo setcap cap_net_raw=ep /usr/bin/ping
  $ ls -l /usr/bin/ping
  -rwxr-xr-x 1 root root /usr/bin/ping  ← 不需要 SUID 位!

  ping 现在只拥有 CAP_NET_RAW,无法执行其他特权操作。
  即使被攻破,攻击者也拿不到完整 root 权限。

3. 完整能力列表与分类

截至 Linux 6.x,系统支持 40+ 个能力。以下是完整分类列表。

3.1 POSIX 基础能力

这些是最基础的权限控制能力,遵循 POSIX 1003.1e 草案:

能力 引入版本 描述
CAP_CHOWN 2.2 任意修改文件的 UID 和 GID
CAP_DAC_OVERRIDE 2.2 绕过文件的读、写、执行权限检查(DAC)
CAP_DAC_READ_SEARCH 2.2 绕过文件的读权限检查,绕过目录的读和执行检查
CAP_FOWNER 2.2 绕过需要进程 UID 与文件 UID 匹配的操作检查
CAP_FSETID 2.2 修改文件时不自动清除 SUID/SGID 位
CAP_KILL 2.2 向任意进程发送信号(绕过权限检查)
CAP_SETGID 2.2 任意操作进程的 GID 和补充组列表
CAP_SETUID 2.2 任意操作进程的 UID(包括 setuid(0))
CAP_SETPCAP 2.2 向其他进程授予/移除能力;修改 securebits
CAP_LINUX_IMMUTABLE 2.2 设置文件的 immutable 和 append-only 属性
CAP_NET_BIND_SERVICE 2.2 绑定低于 1024 的特权端口
CAP_NET_BROADCAST 2.2 套接字广播和监听多播
CAP_NET_ADMIN 2.2 网络管理:接口配置、防火墙、路由表等
CAP_NET_RAW 2.2 使用 RAW 和 PACKET 套接字
CAP_IPC_LOCK 2.2 锁定内存(mlock);使用大页内存
CAP_IPC_OWNER 2.2 绕过 System V IPC 对象的权限检查
CAP_SYS_MODULE 2.2 加载和卸载内核模块
CAP_SYS_RAWIO 2.2 原始 I/O 端口操作;访问 /dev/mem、/dev/kmem
CAP_SYS_CHROOT 2.2 使用 chroot()
CAP_SYS_PTRACE 2.2 使用 ptrace() 追踪任意进程
CAP_SYS_PACCT 2.2 进程记账(acct())
CAP_SYS_ADMIN 2.2 ⚠️ 严重过载:大量系统管理操作
CAP_SYS_BOOT 2.2 重启系统(reboot);加载新内核(kexec)
CAP_SYS_NICE 2.2 修改进程优先级、调度策略、CPU 亲和性
CAP_SYS_RESOURCE 2.2 超越资源限制(rlimit);磁盘配额
CAP_SYS_TIME 2.2 设置系统时钟和硬件时钟
CAP_SYS_TTY_CONFIG 2.2 虚拟终端特权操作(vhangup 等)

3.2 Linux 扩展能力

这些是 Linux 特有的能力,提供了更细粒度的控制:

能力 引入版本 描述
CAP_MKNOD 2.4 创建特殊设备文件(mknod)
CAP_LEASE 2.4 在文件上建立租约(file lease)
CAP_AUDIT_WRITE 2.6.11 向内核审计日志写入记录
CAP_AUDIT_CONTROL 2.6.11 启用/禁用内核审计;修改审计规则
CAP_AUDIT_READ 3.16 通过 netlink 多播读取审计日志
CAP_SETFCAP 2.6.24 设置文件的 capabilities 扩展属性
CAP_MAC_OVERRIDE 2.6.25 覆盖 MAC(Smack LSM 实现)
CAP_MAC_ADMIN 2.6.25 MAC 配置更改(Smack LSM 实现)
CAP_SYSLOG 2.6.37 特权 syslog 操作;读取内核指针地址
CAP_WAKE_ALARM 3.0 设置能唤醒系统的定时器
CAP_BLOCK_SUSPEND 3.5 阻止系统进入挂起/休眠状态

3.3 从 CAP_SYS_ADMIN 拆分出的新能力

CAP_SYS_ADMIN 长期被称为"新的 root",因为它的覆盖范围太广。近年来内核社区持续将功能从中拆分:

能力 引入版本 从 CAP_SYS_ADMIN 拆分出的功能
CAP_BPF 5.8 特权 BPF 操作(加载程序、创建 maps)
CAP_PERFMON 5.8 性能监控(perf_event_open 等)
CAP_CHECKPOINT_RESTORE 5.9 进程检查点/恢复(CRIU)相关操作

趋势:内核社区正持续将 CAP_SYS_ADMIN 拆分为更细粒度的能力,以减少"全能型"能力的安全风险。


4. 五大能力集详解

每个线程拥有五个能力集,每个集合是一个位图,包含零个或多个能力:

                    ┌──────────────────┐
                    │  Bounding Set    │  ← 上限限制(不可恢复地缩小)
                    │  (边界集)         │
                    └────────┬─────────┘
                             │ 限制
                    ┌────────▼─────────┐
                    │  Permitted Set   │  ← 线程可用的最大能力集合
                    │  (许可集)         │
                    └──┬──────┬──────┬─┘
                       │      │      │
              ┌────────▼──┐ ┌─▼──────▼─┐ ┌──────────────┐
              │ Effective │ │Inheritable│ │ Ambient Set  │
              │ Set       │ │ Set      │ │ (环境集)      │
              │ (生效集)   │ │(可继承集) │ │              │
              └───────────┘ └──────────┘ └──────────────┘
                   ↑
             内核权限检查
             使用这个集合

4.1 Permitted(许可集)

定义:线程可以拥有的最大能力集合。它是一个"能力上限"。

特性:

  • 从 Permitted 中移除的能力永久丢失(除非执行具有该能力的特权程序)
  • 新的能力只能通过 execve() 执行具有文件能力的程序来获得
  • Effective 和 Inheritable 集合必须是 Permitted 的子集
# 查看当前进程的 Permitted 集
cat /proc/self/status | grep CapPrm
# CapPrm: 0000000000000000

# 解码为可读名称
capsh --decode=0000000000000000

4.2 Inheritable(可继承集)

定义:在 execve() 执行新程序时可以跨 exec 保留的能力集合。

特性:

  • 历史上这个集合的实际作用有限——非 root 进程执行程序时,Inheritable 集通常被清空
  • 与文件的 Inheritable 集进行交集运算后,决定新进程的 Permitted 集
  • 这正是 Ambient 集被引入的原因——弥补 Inheritable 在非 root 场景下的不足

4.3 Effective(生效集)

定义:内核用来实际进行权限检查的能力集合。

特性:

  • 这是唯一"起作用"的集合——内核检查 capable() 时查询的是 Effective 集
  • 通常是 Permitted 的子集
  • 可以通过 libcap API 或 prctl() 动态开关
// 内核中检查能力的典型代码
if (!capable(CAP_NET_BIND_SERVICE))
    return -EACCES;
// 等价于检查:CAP_NET_BIND_SERVICE 是否在 Effective 集中

4.4 Bounding(边界集)

定义:一个不可恢复的上限限制,限定在 execve() 期间能获得的能力。

特性:

  • 只能缩小(通过 prctl(PR_CAPBSET_DROP, ...)),无法扩大
  • 一旦某个能力从 Bounding 集中移除,所有后代进程都无法再获得它
  • 这是实现"纵深防御"的关键机制
# 查看当前进程的 Bounding 集
cat /proc/self/status | grep CapBnd
# CapBnd: 000001ffffffffff

# 通过 capsh 查看
capsh --print | grep Bounding

4.5 Ambient(环境集)

定义(Linux 4.3+):解决非 root 进程执行程序时无法保留能力的历史性缺陷

特性:

  • 在执行非特权程序时自动保留并添加到新进程的 Permitted 和 Effective 集中
  • 一个能力要进入 Ambient 集,必须同时存在于 Permitted 和 Inheritable 集中
  • 解决了"非 root 进程无法将能力传递给子进程"的问题
Ambient 集的价值:

问题场景:
  $ ping 8.8.8.8
  ping 需要 CAP_NET_RAW 能力

  旧方案:SUID root → ping 以 root 运行 → 安全风险
  新方案:Ambient Set → ping 只拥有 CAP_NET_RAW → 最小权限

  父进程(bash, 无特殊权限)
      │ execve("/usr/bin/ping")
      │ ping 有文件能力 cap_net_raw=pie
      ▼
  子进程(ping)
      Permitted: CAP_NET_RAW  ← 从文件能力获得
      Ambient:   CAP_NET_RAW  ← 自动添加到生效集
      Effective: CAP_NET_RAW  ← 内核权限检查通过!

5. 文件能力(File Capabilities)

从 Linux 2.6.24 起,能力可以附加到可执行文件上,存储在文件的 security.capability 扩展属性中。

文件能力的三个组成部分

组件 含义
Permitted (p) 自动授予执行该文件进程的能力
Inheritable (i) 与进程的 Inheritable 集做"与"运算
Effective (e) 单个位:如果设置,新获得的许可能力自动变为生效

版本

版本 内核版本 说明
VFS_CAP_REVISION_1 2.6.24 最初版本,32 位掩码
VFS_CAP_REVISION_2 2.6.25 64 位掩码,支持更多能力
VFS_CAP_REVISION_3 4.14 命名空间化文件能力

文件能力 vs SUID

# 旧方式:SUID(赋予完整 root 权限)
chmod u+s /usr/bin/myapp

# 新方式:文件能力(仅赋予所需能力)
setcap cap_net_bind_service=ep /usr/bin/myapp
#                                    ↑↑
#                                    e: effective bit 设置
#                                    p: permitted set

6. 能力继承规则:execve() 时的完整变换

6.1 标准变换算法

当进程执行 execve() 时,内核按以下公式计算新进程的能力集:

设:
  P(X)  = execve() 前的旧进程能力集 X
  P'(X) = execve() 后的新进程能力集 X
  F(X)  = 文件的文件能力集 X

变换公式:

  P'(ambient)     = (文件是特权文件) ? 空集 : P(ambient)

  P'(permitted)   = (P(inheritable) ∩ F(inheritable))
                  ∪ (F(permitted) ∩ P(bounding))
                  ∪ P'(ambient)

  P'(effective)   = F(effective_bit) ? P'(permitted) : P'(ambient)

  P'(inheritable) = P(inheritable)     ← 不变

  P'(bounding)    = P(bounding)        ← 不变

通俗解释:

  1. Ambient:如果不是执行特权文件(SUID 或文件能力标记),保留 Ambient 集
  2. Permitted:新许可集 = (可继承交集) + (文件许可 ∩ 边界限制) + 环境能力
  3. Effective:如果文件 effective bit 被设置,所有新许可能力自动生效;否则只生效环境能力
  4. Inheritable 和 Bounding:保持不变

6.2 Root 用户的特殊行为

当进程的 real UID 或 effective UID 为 0(root)时执行程序:

文件的 Permitted 和 Inheritable 集被忽略!
被视为全 1(所有能力)。

因此 root 执行任何程序都会获得其 Bounding 集内的所有能力。

可通过 SECBIT_NOROOT 禁用此行为。

6.3 UID 变换的影响

进程 UID 从 0 变为非 0 时:
  ├─ Permitted 集被清空
  └─ Effective 集被清空

除非设置了 SECBIT_KEEP_CAPS,才能保留能力。
# 示例:从 root 切换到普通用户,保留 CAP_NET_RAW
capsh --secbits=0x10 -- -c '
    ping -c 1 8.8.8.8
'
# 0x10 = SECBIT_KEEP_CAPS 设置

7. Securebits:纯能力环境

Securebits 允许创建一个完全基于能力的执行环境,彻底禁用对 UID=0 的特殊处理:

Securebit 位值 含义
SECBIT_KEEP_CAPS 0x10 UID 变为非 0 时保留许可能力
SECBIT_NO_SETUID_FIXUP 0x20 UID 切换时不自动调整能力集
SECBIT_NOROOT 0x40 Root 执行程序时自动获得所有能力
SECBIT_NO_CAP_AMBIENT_RAISE 0x80 禁止通过 prctl 添加 Ambient 能力

每个标志都有对应的 _LOCKED 版本,设置后该标志不可逆

# 创建一个纯能力环境(root 也不享有特权)
capsh --secbits=0x2f -- -c 'id; cat /proc/self/status | grep Cap'
# 0x2f = KEEP_CAPS|NO_SETUID_FIXUP|NOROOT 及其锁定位

8. 用户命名空间与 Capabilities

用户命名空间(User Namespace)与 Capabilities 深度结合,实现了"容器中的 root":

宿主机:
  进程 A (UID=1000) ─── 无特殊能力 ─── 普通用户

  创建用户命名空间后:
  进程 A 在新命名空间中映射为 UID=0
  进程 A 获得该命名空间内的完整能力集
  但这些能力只在该命名空间内有效!

  ┌─────────────────────────────────┐
  │  User Namespace (容器)           │
  │  UID=0 (root in container)      │
  │  Full capabilities              │
  │  ├─ 可以挂载文件系统             │
  │  ├─ 可以绑定端口                 │
  │  └─ 可以修改网络配置             │
  └───────────────┬─────────────────┘
                  │
  宿主机视角:     │  UID=1000, 无特权
                  │  容器内的操作不影响宿主机
# 在用户命名空间中体验"root"
unshare --user --map-root-user bash
# 现在你是"容器内的 root"
whoami          # root
id              # uid=0(root)
ping 8.8.8.8    # 可能仍然失败(CAP_NET_RAW 受宿主机限制)

9. 实战命令大全

9.1 进程能力查看

# 查看当前 shell 的能力
capsh --print

# 查看特定进程的能力
cat /proc/$(pidof nginx)/status | grep -i cap
# CapInh: 0000000000000000  (Inheritable)
# CapPrm: 0000000000000000  (Permitted)
# CapEff: 0000000000000000  (Effective)
# CapBnd: 000001ffffffffff  (Bounding)
# CapAmb: 0000000000000000  (Ambient)

# 解码能力位图
capsh --decode=000001ffffffffff

# 查看进程的可读能力列表
getpcaps $(pidof nginx)

# 查看所有进程的能力
ps -eo pid,comm,cap_eff,cap_prm --sort=-cap_eff | head -20

9.2 文件能力管理(getcap/setcap)

# ========== 查看文件能力 ==========

# 查看单个文件
getcap /usr/bin/ping
# /usr/bin/ping cap_net_raw=ep

# 递归查看目录
getcap -r /usr/bin/
getcap -r / 2>/dev/null

# ========== 设置文件能力 ==========

# 格式:setcap <能力名>=<集合标志> <文件>

# 设置 Permitted + Effective(最常用)
sudo setcap cap_net_raw=ep /usr/bin/ping
#                        ↑↑
#                        e: effective bit 设置
#                        p: permitted 设置

# 仅设置 Permitted(不自动生效)
sudo setcap cap_net_bind_service=p /usr/bin/myapp

# 设置 Permitted + Inheritable
sudo setcap cap_dac_override=ip /usr/bin/myapp

# 设置多个能力
sudo setcap 'cap_net_raw,cap_net_bind_service=ep' /usr/bin/myapp

# ========== 移除文件能力 ==========

# 移除所有能力
sudo setcap -r /usr/bin/myapp

# ========== 验证文件能力 ==========
getcap /usr/bin/ping
# /usr/bin/ping cap_net_raw=ep

9.3 能力测试与调试

# ========== capsh 工具 ==========

# 以特定能力运行命令
capsh --caps="cap_net_raw=ep" -- -c "ping -c 1 8.8.8.8"

# 以特定能力启动 shell
capsh --caps="cap_net_bind_service=ep cap_chown=ep" --

# 删除特定能力
capsh --drop=cap_sys_admin -- -c "mount /dev/sda1 /mnt"
# mount 会失败:权限不足

# 完全无能力运行
capsh --caps="=" -- -c "cat /etc/shadow"
# 即使 root 也读不了(如果 DAC 也拒绝了)

# ========== 解码能力掩码 ==========
capsh --decode=0000000000003000
# 0x3000 = CAP_NET_ADMIN | CAP_NET_RAW

# ========== 查看系统支持的能力列表 ==========
capsh --supported

9.4 libcap 编程接口

#include <sys/capability.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    cap_t caps;
    cap_value_t cap_list[2];

    // 获取当前进程的能力
    caps = cap_get_proc();
    if (caps == NULL) {
        perror("cap_get_proc");
        exit(1);
    }

    // 以文本形式打印
    char *cap_text = cap_to_text(caps, NULL);
    printf("Current capabilities: %s\n", cap_text);
    cap_free(cap_text);

    // 添加 CAP_NET_RAW 到 Permitted 和 Effective
    cap_list[0] = CAP_NET_RAW;
    cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET);
    cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET);

    // 应用新的能力集
    if (cap_set_proc(caps) == -1) {
        perror("cap_set_proc");
        cap_free(caps);
        exit(1);
    }

    printf("Successfully set CAP_NET_RAW\n");

    // 释放
    cap_free(caps);
    return 0;
}
# 编译
gcc -o cap_demo cap_demo.c -lcap
sudo ./cap_demo

libcap 核心 API 速查:

API 功能
cap_get_proc() 获取当前进程的能力集
cap_set_proc() 设置当前进程的能力集
cap_get_file() 获取文件的能力
cap_set_file() 设置文件的能力
cap_get_flag() 获取特定能力的标志状态
cap_set_flag() 设置特定能力的标志状态
cap_clear() 清空能力集
cap_to_text() 将能力集转换为文本
cap_from_text() 从文本解析能力集
cap_free() 释放能力集内存

10. Docker 容器与 Capabilities

10.1 Docker 默认授予的能力

Docker 默认授予容器 14 种能力,远少于 root 的全部能力:

默认授予的能力 用途
CAP_CHOWN 修改文件所有者
CAP_DAC_OVERRIDE 绕过文件权限检查
CAP_FSETID 修改文件时不清理 SUID/SGID
CAP_FOWNER 绕过文件所有者检查
CAP_MKNOD 创建设备文件
CAP_NET_RAW 使用原始套接字(ping)
CAP_SETGID 修改 GID
CAP_SETUID 修改 UID
CAP_SETFCAP 设置文件能力
CAP_SETPCAP 修改能力集
CAP_NET_BIND_SERVICE 绑定特权端口
CAP_SYS_CHROOT 使用 chroot
CAP_KILL 发送信号
CAP_AUDIT_WRITE 写入审计日志

Docker 默认移除的能力(安全原因):

CAP_SYS_MODULE     ← 防止加载内核模块
CAP_SYS_RAWIO      ← 防止直接访问 I/O 端口
CAP_SYS_PACCT      ← 防止进程记账
CAP_SYS_ADMIN      ← 防止大量系统管理操作
CAP_SYS_NICE       ← 防止修改调度优先级
CAP_SYS_RESOURCE   ← 防止超越资源限制
CAP_SYS_TIME       ← 防止修改系统时钟
CAP_SYS_TTY_CONFIG ← 防止虚拟终端操作
CAP_AUDIT_CONTROL  ← 防止修改审计规则
CAP_MAC_ADMIN      ← 防止修改 MAC 策略
CAP_MAC_OVERRIDE   ← 防止绕过 MAC
CAP_SYSLOG         ← 防止特权 syslog
... 以及更多

10.2 最小权限容器配置

# 极致安全:移除所有能力,仅加回必需的
docker run -d \
  --name secure-app \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --security-opt no-new-privileges:true \
  --read-only \
  --tmpfs /tmp:noexec,nosuid \
  nginx:alpine

# 参数说明:
# --cap-drop=ALL              → 移除所有能力
# --cap-add=NET_BIND_SERVICE  → 仅加回绑定端口能力
# no-new-privileges:true      → 禁止进程获取新能力
# --read-only                 → 根文件系统只读
# --tmpfs /tmp:noexec,nosuid  → tmpfs 禁止执行

10.3 Kubernetes 中的 Capabilities

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  containers:
  - name: app
    image: nginx:alpine
    securityContext:
      capabilities:
        drop:
          - ALL                     # 移除所有能力
        add:
          - NET_BIND_SERVICE        # 仅加回必需的能力
      readOnlyRootFilesystem: true
      allowPrivilegeEscalation: false
      runAsNonRoot: true
      runAsUser: 1000

11. Capabilities 与 SUID 的对比

维度 SUID Capabilities
权限粒度 全部 root 权限 精确到单个能力
安全风险 高(漏洞→root shell) 低(漏洞→有限能力)
配置方式 chmod u+s setcap
存储位置 文件权限位(inode mode) 文件扩展属性(xattr)
继承性 仅对可执行文件有效 可跨 exec 继承(Ambient)
可审计性 难追踪(都是 root) 可追踪(精确到能力)
兼容性 所有 UNIX 系统 Linux 2.6.24+

迁移 SUID 到 Capabilities

# 传统 SUID 方式
ls -l /usr/bin/ping
# -rwsr-xr-x 1 root root /usr/bin/ping

# 迁移步骤:
# 1. 设置文件能力
sudo setcap cap_net_raw=ep /usr/bin/ping

# 2. 移除 SUID 位
sudo chmod u-s /usr/bin/ping

# 3. 验证
ls -l /usr/bin/ping
# -rwxr-xr-x 1 root root /usr/bin/ping  ← SUID 已移除

getcap /usr/bin/ping
# /usr/bin/ping cap_net_raw=ep  ← 能力已设置

ping -c 1 8.8.8.8  # 仍然可以正常工作

12. 安全加固最佳实践

12.1 最小权限原则

# ✅ 好的实践:移除所有默认能力,只加必需的
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx

# ✅ 检查当前能力,关闭不需要的
capsh --print
capsh --drop=CAP_SYS_ADMIN,CAP_SYS_MODULE --

# ❌ 坏的做法:赋予过多能力
docker run --cap-add=ALL nginx

# ❌ 更坏的做法:特权模式
docker run --privileged nginx

12.2 能力审计 Checklist

# 1. 检查所有 SUID 文件(潜在的替换目标)
find / -perm -4000 -type f 2>/dev/null

# 2. 检查所有文件能力
getcap -r / 2>/dev/null

# 3. 检查运行的容器能力
for c in $(docker ps -q); do
    echo "Container: $c"
    docker inspect $c | jq '.[0].HostConfig.CapAdd, .[0].HostConfig.CapDrop'
done

# 4. 审查进程的能力
ps -eo pid,comm,user,cap_eff --sort=-cap_eff | grep -v "0000000000000000"

12.3 纵深防御组合

# 完整的容器安全配置:多层次防御
docker run -d \
  --name defense-in-depth \
  --cap-drop=ALL \                      # Capabilities:移除所有
  --cap-add=NET_BIND_SERVICE \          # 仅加回必需的
  --security-opt no-new-privileges \    # 禁止获取新能力
  --security-opt seccomp=strict.json \  # Seccomp:系统调用过滤
  --security-opt apparmor=custom-prof \ # AppArmor:文件访问控制
  --read-only \                         # 只读根文件系统
  --tmpfs /tmp:noexec,nosuid \          # 临时文件系统限制
  --user 1000:1000 \                    # 非 root 用户运行
  nginx:alpine

13. Capabilities 提权攻击与防范

13.1 已知的危险能力

以下能力如果配置不当,可能被用于提权:

能力 攻击向量 风险等级
CAP_SYS_ADMIN mount、pivot_root、unshare 等大量操作 🔴 极高
CAP_SYS_MODULE 加载恶意内核模块 🔴 极高
CAP_SYS_RAWIO 直接内存访问、修改内核 🔴 极高
CAP_SYS_PTRACE 注入任意进程 🔴 高
CAP_SETUID setuid(0) 直接获得 root 🔴 高
CAP_SETFCAP 给任意文件设置能力 🔴 高
CAP_DAC_OVERRIDE 修改 /etc/shadow 添加 root 用户 🔴 高
CAP_CHOWN 修改关键文件所有者 🟡 中
CAP_FOWNER 修改关键文件权限 🟡 中
CAP_DAC_READ_SEARCH 读取 /etc/shadow 🟡 中

13.2 防护措施

# 1. 审计文件能力
getcap -r / 2>/dev/null | grep -E "cap_sys_admin|cap_setuid|cap_dac_override"
# 确保没有意外的高权限能力

# 2. 使用 Bounding Set 限制整个进程树
# 在系统启动早期设置
capsh --drop=cap_sys_admin,cap_sys_module,cap_sys_rawio --

# 3. 结合 Seccomp 防止能力绕过
# Seccomp 可以阻止可能导致提权的系统调用

# 4. 启用 Securebits 锁定
# SECBIT_NOROOT_LOCKED 确保即使是 SUID-root 程序也不获得全部能力

14. 总结

核心要点

要点 说明
拆分 root 权限 将传统 root 全部特权拆分为 40+ 个独立能力
五大能力集 Permitted / Inheritable / Effective / Bounding / Ambient
文件能力替代 SUID 比 SUID 更安全、更精细的权限赋予方式
Bounding Set 不可逆 实现纵深防御的关键机制
Ambient Set 解决继承 让非 root 进程的子进程也能保留能力
容器默认受限 Docker 默认移除 20+ 种危险能力
最小权限原则 永远使用 --cap-drop=ALL --cap-add=<必需的>

推荐资源


免责声明:本文内容基于 Linux 内核文档和手册页编写,适用于 Linux 2.2+ 内核系列。具体能力列表和 API 行为可能因内核版本和发行版配置而异,请以实际运行环境为准。