```
██╗ ██╗██████╗
██║ ██║██╔══██╗
██║ ██║██║ ██║
██║ ██║██║ ██║
███████╗██║██████╔╝
╚══════╝╚═╝╚═════╝
```
— "Linux 正在消亡" —
系统发现绕过 LSM 安全保证的内核代码路径
大门从未被攻破,只是被绕过了。
Linux 安全模块框架有一个核心保证,已经保持了 20 多年:
安全模块只能增加限制。它们永远不能移除限制。
这个保证是正确的。LID 并没有打破它。
LID 发现了完全绕过 LSM 钩子的内核代码路径——执行安全敏感操作而不咨询 LSM 框架的子系统。安全检查是正确的。问题是内核从未询问过。
每个发现有两个不同的维度,不应混为一谈:
架构上的盲点。问题不是“攻击者能否利用这个?”而是:
如果发生了一个安全敏感操作,而执行层甚至从未对其进行评估,那么你就存在一个可见性差距——无论攻击者今天是否能够实际利用它。这对合规性、取证和纵深防御假设很重要。
现实世界中的可利用性问题:
这两者是不同的。 一个发现可以是关键的可见性差距(你的监控是盲目的),而不一定是一个实际的权限提升(攻击者已经需要 root)。相反,一个发现可以是一个直接提权路径,具有最低的先决条件。
| 发现 | 可见性差距 | 实际提权 |
|---|---|---|
| LID-001 | 关键 — AppArmor 什么都看不到,审计日志为空,零取证痕迹 | 有限 — 需要 root 或 CAP_BPF+CAP_PERFMON(已有特权)。不是权限提升。影响:策略规避 + 审计盲区。 |
| LID-002 | 高 — security_file_receive() 从未触发,fd 传递对所有 LSM 不可见 | 高 — 通过 io_uring 从无特权用户空间工作。无需任何特权即可跨越 LSM 强制边界。 |
| LID-003 | 高 — security_sb_mount() 被绕过,AppArmor 挂载策略成为死代码 | 中 — 需要挂载命名空间访问(用户命名空间中的 CAP_SYS_ADMIN)。在许多容器配置中可用。 |
| LID-004 | 关键 — AppArmor 什么都看不到,零 BPF 钩子(0/9),任何 BPF 令牌操作均无审计痕迹 | 中 — 需要主机委托 bpffs + 用户命名空间中的 CAP_BPF。在具有 BPF 委托的容器运行时(LXD/Incus)中可用。 |
| LID-005 | 中 — 容器接口上的 tc 出站分类器永远不评估 AF_XDP 流量 | 有限 — 绕过容器 eth0 上的 tc 出站(已验证)。Cilium 未被绕过——在节点侧 veth 入站加强并验证源 IP(已测试)。影响限于仅使用 tc 出站过滤的普通 Docker 设置。 |
每个发现都有特定的内核/配置/权限要求。如果你的环境不匹配,该发现将无法复现。
| 条件 | 要求 | 注释 |
|---|---|---|
| 内核版本 | 5.x+ | 已在 5.15、6.1、6.6、6.8 上测试 |
CONFIG_BPF_SYSCALL | =y | 所有主要发行版默认开启 |
CONFIG_BPF_KPROBE_OVERRIDE | =y | Ubuntu/Debian 启用,RHEL 不启用 |
CONFIG_SECURITY_APPARMOR | =y | 目标 LSM 必须为 AppArmor |
| AppArmor 配置文件 | 强制模式,目标路径上有拒绝规则 | 适用于任何基于路径的拒绝规则 |
| 权限 | root 或 CAP_BPF + CAP_PERFMON | 不能以无特权方式运行 |
kernel.lockdown | none 或 integrity | confidentiality 模式阻止 kprobe 附加 |
kernel.unprivileged_bpf_disabled | 无关 | 无论如何都需要 CAP_BPF |
fs.protected_hardlinks | 跨用户链接需为 0 | 1(默认)仍允许同用户硬链接 |
| SELinux 代替 AppArmor | 不工作 | SELinux 基于 inode,而不是基于路径名 |
| 条件 | 要求 | 注释 |
|---|---|---|
| 内核版本 | 6.0+ | IORING_MSG_SEND_FD 在 6.0 中添加 |
CONFIG_IO_URING | =y | 所有主要发行版默认开启 |
| 权限 | 无 | 从无特权用户空间工作 |
io_uring_disabled sysctl | 0(默认) | 2 阻止无特权用户,1 阻止所有 |
| 目标 LSM | 任意(SELinux、AppArmor、Smack) | security_file_receive() 是一个通用 LSM 钩子 |
kernel.lockdown | 无关 | 不涉及 BPF |
| 条件 | 要求 | 注释 |
|---|---|---|
| 内核版本 | 6.9+ | BPF 令牌在 6.9 中引入 |
CONFIG_BPF_SYSCALL | =y | 所有主要发行版默认开启 |
CONFIG_SECURITY_APPARMOR | =y | Ubuntu/Debian 默认 |
| bpffs 启用了委托 | 是 | 主机必须使用 delegate_* 选项挂载 |
| 权限 | 用户命名空间中的 CAP_BPF | 用户命名空间 root 可轻易获得 |
| SELinux 代替 AppArmor | 不受影响 | SELinux 实现了所有 9 个 BPF 钩子 |
| 条件 | 要求 | 注释 |
|---|---|---|
| 内核版本 | 5.2+ | fsopen/fsmount 在 5.2 中引入 |
CONFIG_SECURITY_APPARMOR | =y | 仅影响 AppArmor |
| 权限 | 用户命名空间中的 CAP_SYS_ADMIN | 可通过 unshare -m 获取 |
| SELinux 代替 AppArmor | 不工作 | SELinux 实现了 security_sb_kern_mount() |
| 容器运行时 | 取决于 seccomp 过滤器 | Docker 默认 seccomp 阻止 fsopen — Podman/LXC 可能不阻止 |
| 条件 | 要求 | 注释 |
|---|---|---|
| 内核版本 | 4.18+ | AF_XDP 在 4.18 中引入 |
CONFIG_XDP_SOCKETS | =y | 所有主要发行版默认开启 |
| 权限 | 仅 CAP_NET_RAW | Docker、Kubernetes Pod 默认具备 |
| 容器运行时 | Docker、K8s、LXC | 默认权限集 |
| 基于 tc 的网络策略 | 是 | Cilium eBPF、Calico、tc u32/flower |
| 环境 | LID-001 | LID-002 | LID-003 | LID-004 | LID-005 |
|---|---|---|---|---|---|
| Ubuntu 22.04+(AppArmor,默认) | 有效 | 有效 | 有效 | 有效(6.9+) | 有效 |
| Debian 12+(AppArmor) | 有效 | 有效 | 有效 | 有效(6.9+) | 有效 |
| RHEL/Fedora(SELinux) | 否 | 有效 | 否 | 否 | 有效 |
lockdown=confidentiality | 否 | 有效 | 有效 | 部分 | 有效 |
| 无特权用户 | 否 | 有效 | 取决于用户命名空间 | 取决于 bpffs 委托 | 否 |
| 容器(无 CAP_BPF) | 否 | 取决于 io_uring | 取决于 seccomp | 否 | 有效 |
| 容器(已丢弃 CAP_NET_RAW) | 否 | 取决于 | 取决于 | 否 | 否 |
| ID | 向量 | 目标 | 发生了什么 |
|---|---|---|---|
| LID-001 | eBPF kprobe 路径名重写 | AppArmor | kprobe 在 copy_from_user 之前重写文件名 → AppArmor 检查错误的路径 |
| LID-002 | io_uring MSG_RING SEND_FD | SELinux、AppArmor、Smack | fd 传递跳过了 security_file_receive() — 而所有其他 fd 传递都会调用它 |
| LID-003 | 新挂载 API(fsopen/fsmount) | AppArmor | security_sb_mount() 从未被调用 — AppArmor 唯一的挂载钩子被绕过 |
| LID-004 | BPF 令牌委托 | AppArmor、Smack | 零 BPF 钩子 — 令牌创建、使用、能力委托完全不可见 |
| LID-005 | AF_XDP __dev_direct_xmit | tc 出站、Cilium、Calico | 从默认 Docker 的复制模式 TX 绕过 tc 分类器 — 伪造的数据包到达网桥 |
每个发现都遵循相同的模式:``` ┌─────────────────────────────────────────────────────────────┐ │ THE LID PATTERN │ │ │ │ Kernel Subsystem A LSM Framework │ │ (eBPF / io_uring / mount API) (AppArmor / SELinux) │ │ │ │ ┌───────────────────┐ │ │ │ Performs operation │──── should call ──── security_*() │ │ │ or manipulates │ but │ │ │ security input │ DOESN'T ██ │ │ └───────────────────┘ │ │ │ │ The LSM framework is correct. │ │ The kernel just doesn't always use it. │ └─────────────────────────────────────────────────────────────┘
两个内核子系统。不兼容的信任假设。一个漏洞。
<br>
---
## LID-001: eBPF 路径名重写