Skip to main content

Linux Kernel 历史上最著名的重大事故梳理

11 min read
tip

跟同事闲聊

Linux kernel 有没有发生过 "重大事故"?有,而且不少。但如果你说的是 "像飞机失事那种一次性把整个 Linux 打爆" 的事故,其实不多。

Linux kernel 更常见的 "重大事故" 是三类:长期潜伏影响几乎所有发行版的本地提权漏洞、牵动整个行业的体系结构级安全事件、在文件系统或内存管理里引发数据丢失或严重性能代价的设计或回归问题。

下面按时间线梳理,然后挑四个最值得细讲的事件做深度分析。


Linux Kernel 重大事故全景

年份事件类型子系统
2008vmsplice 提权 (CVE-2008-0600) — 用户态指针校验不充分,本地提权提权fs
2009ext4 数据丢失风波 — delayed allocation 语义错位致崩溃后文件截零可靠性fs
2009sock_sendpage (CVE-2009-2692) — 函数指针未初始化,NULL 页映射提权提权net
2010RDS 协议提权 (CVE-2010-3904) — 参数检查不充分,本地 root提权net
2014Towelroot (CVE-2014-3153) — futex_requeue 路径竞争条件,Android 武器化提权kernel/futex
2016Dirty COW (CVE-2016-5195) — COW 竞争条件,影响 2.x~4.x,已被实战利用提权mm
2017Stack Clash (CVE-2017-1000364) — stack guard page 过小可被跳过提权mm
2018Meltdown / Spectre — CPU 推测执行侧信道,迫使 PTI/retpoline 引入架构arch
2019TCP SACK Panic (CVE-2019-11477) — SACK+小 MSS 远程打崩系统DoSnet
2021Sequoia (CVE-2021-33909) — VFS 层整数转换错误,本地提权提权fs/VFS
2022Dirty Pipe (CVE-2022-0847) — pipe_buffer flags 未初始化,写只读 page cache提权fs/pipe
2024nf_tables UAF (CVE-2024-1086) — netfilter use-after-free,本地提权提权net
- 年份: 2008
事件: "**vmsplice 提权** (CVE-2008-0600)
des: 用户态指针校验不充分,本地提权"
类型: 提权
子系统: fs
- 年份: 2009
事件: "**ext4 数据丢失风波**
des: delayed allocation 语义错位致崩溃后文件截零"
类型: 可靠性
子系统: fs
- 年份: 2009
事件: "**sock_sendpage** (CVE-2009-2692)
des: 函数指针未初始化,NULL 页映射提权"
类型: 提权
子系统: net
- 年份: 2010
事件: "**RDS 协议提权** (CVE-2010-3904)
des: 参数检查不充分,本地 root"
类型: 提权
子系统: net
- 年份: 2014
事件: "**Towelroot** (CVE-2014-3153)
des: futex_requeue 路径竞争条件,Android 武器化"
类型: 提权
子系统: kernel/futex
- 年份: 2016
事件: "**Dirty COW** (CVE-2016-5195)
des: COW 竞争条件,影响 2.x~4.x,已被实战利用"
类型: 提权
子系统: mm
- 年份: 2017
事件: "**Stack Clash** (CVE-2017-1000364)
des: stack guard page 过小可被跳过"
类型: 提权
子系统: mm
- 年份: 2018
事件: "**Meltdown / Spectre**
des: CPU 推测执行侧信道,迫使 PTI/retpoline 引入"
类型: 架构
子系统: arch
- 年份: 2019
事件: "**TCP SACK Panic** (CVE-2019-11477)
des: SACK+小 MSS 远程打崩系统"
类型: DoS
子系统: net
- 年份: 2021
事件: "**Sequoia** (CVE-2021-33909)
des: VFS 层整数转换错误,本地提权"
类型: 提权
子系统: fs/VFS
- 年份: 2022
事件: "**Dirty Pipe** (CVE-2022-0847)
des: pipe_buffer flags 未初始化,写只读 page cache"
类型: 提权
子系统: fs/pipe
- 年份: 2024
事件: "**nf_tables UAF** (CVE-2024-1086)
des: netfilter use-after-free,本地提权"
类型: 提权
子系统: net

另外提一句:2024 年的 XZ 后门 很重大,但它不是 Linux kernel 本身的事故。它是 xz/liblzma 供应链后门,主要波及用户空间/构建链,而非内核源码本身。


Dirty COW (CVE-2016-5195) — 最经典的内核提权

背景

Dirty COW 的官方名称是 CVE-2016-5195,潜伏在 Linux kernel 中超过 9 年,影响从 2.x 到 4.x 的几乎所有版本。它之所以叫 "Dirty COW",是因为漏洞出在内存管理的 写时复制(Copy-On-Write, COW) 机制上。

技术细节

漏洞位于 mm/gup.c 中的 get_user_pages() 路径。核心问题是:当一个进程以只读方式 MAP_SHARED 映射了一个文件,然后尝试写入时,内核会触发 COW 创建一个私有副本。但在多线程竞争条件下,存在一个时间窗口:

  1. 线程 A 对只读映射执行写入 → 内核触发 COW
  2. 在 COW 完成但权限重新检查之前,线程 B 修改了页表
  3. 内核错误地认为线程 A 有写入权限,直接将数据写入了底层的 page cache(而不是私有副本)

结果就是:一个本应只读的映射,被成功修改了底层文件内容,进而可以实现本地提权。

影响

  • 影响 Linux kernel 2.6.22+ 到 4.8 的几乎所有版本
  • 官方记录明确提到 2016 年 10 月已被实战利用
  • Red Hat、Ubuntu、Debian 全部紧急出补丁
  • PoC 流传极广,利用思路相对稳定

为什么它值得记住

Dirty COW 的 "经典" 之处在于:漏洞原理简单优雅、潜伏时间极长、影响范围极广。它是内核安全教材中几乎必讲的案例——一个最基础的 mm 层机制,在特定竞争条件下暴露出完全违背直觉的行为。 (国家漏洞数据库)


Meltdown / Spectre — 体系级大改

背景

2018 年初公开的 Meltdown 和 Spectre 严格说不只是 kernel 自身的 bug,根子在 CPU 的推测执行(speculative execution)侧信道(side channel)。但它对 Linux kernel 的冲击属于 "必须记进内核史" 的级别。

技术细节

这两组漏洞的核心思路类似:CPU 在推测执行时会访问本不该访问的数据,虽然推测执行最终会被回滚,但留下的缓存痕迹不会消失。攻击者可以通过测量缓存访问时间,推断出被推测执行读取的敏感信息。

  • Meltdown:利用的是乱序执行中权限检查的延迟窗口,读内核内存
  • Spectre:利用的是分支预测的训练,诱导 CPU 推测执行恶意路径

对 Linux kernel 来说,这意味着:

  • 用户态和内核态的页表隔离不再可靠
  • 内核地址空间需要独立映射

内核的应对

Linux 引入了 PTI(Page Table Isolation):每个进程现在有两套页表——一套给用户态(只映射必要信息),一套给内核态。每次用户态→内核态切换都需要切换页表。

Spectre 则催生了 retpoline(return trampoline)等一系列编译器级别的缓解手段,以及针对特定变种(Spectre v1、v2、v4 等)的内核补丁。

影响

  • 几乎所有现代 x86 处理器受影响
  • 系统性能代价:根据工作负载不同,2%~30% 不等
  • 内核代码复杂度永久性增加
  • 后续多年仍在出现新的变种(至今已有 Spectre v1~v5、Meltdown v3/v3.1 等)

为什么它值得记住

Meltdown/Spectre 改变了整个行业对 "安全边界" 的认知——硬件设计假定一旦被打破,软件层要付出巨大的代价来兜底。Linux kernel 在这里的角色是最具代表性的:它不得不背负永久性的复杂度和性能代价,来为一个它从未参与设计的硬件漏洞买单。 (Linux内核档案馆)


ext4 数据丢失风波 — 可靠性事故的代表

背景

2009 年左右,ext4 正处于推广初期,取代 ext3 成为主流 Linux 发行版的默认文件系统。但很快,大量用户报告了一个令人不安的现象:系统崩溃或断电重启后,文件被成功重命名了,但内容变成了 0 字节。LWN 当时直接以 "ext4 and data loss" 为题做了专题讨论。

技术细节

这不是传统安全漏洞,而是一次语义设计错位

ext4 引入了 delayed allocation(延迟分配)——写入文件时,内核先把数据缓冲在内存中,延迟实际分配磁盘块的时间。这能显著提升性能,因为可以合并多次小写入、选择更优的磁盘布局。

问题在于:很多应用程序的保存逻辑是:

  1. 写入新文件内容
  2. 调用 rename() 原子替换旧文件

在 ext3 上,这种行为是安全的——因为 ext3 在 rename() 时会强制刷盘。但在 ext4 的 delayed allocation 下,rename() 成功后,新文件的数据可能还在内存里,根本没有落盘。一旦断电,就得到了一个 "重命名成功但内容为空" 的文件。

社区的应对

内核社区围绕着 "如何在不明显牺牲性能的前提下,尽量缩小这个风险窗口" 做了多轮补丁:

  • auto_da_alloc 挂载选项的引入
  • rename()fsync() 等关键路径增加隐式刷盘
  • open() + O_TRUNC 等危险模式的处理优化

ext4 的 data=ordered 模式后来也做了行为调整。

为什么它值得记住

这次事件的本质是:文件系统的性能优化,在没有充分语义契约的情况下,打破了应用层对 POSIX 语义的合理假设。它与其说是 "bug",不如说是一次 distributed semantic mismatch——kernel 开发者认为 "应用应该 fsync",应用开发者认为 "rename 成功就是安全的"。这种边界问题至今仍在内核开发中反复出现。 (LWN.net)


Dirty Pipe (CVE-2022-0847) — 现代内核仍有穿透性漏洞

背景

2022 年初公开的 Dirty Pipe,从名字就看得出是在向 Dirty COW "致敬"。官方描述很直接:Linux kernel 对 pipe buffer 的处理存在问题,导致非特权用户能写入只读文件对应的 page cache。Red Hat 和 Ubuntu 都把它当成高影响内核漏洞处理。

技术细节

漏洞在 pipe 子系统的 pipe_buffer 结构中。每个 pipe buffer 有一个 flags 字段,其中一位标记着 PIPE_BUF_FLAG_CAN_MERGE——表示这个 buffer 是否可以和新写入的数据合并。

问题出在:当创建一个新的 pipe buffer 时,flags 字段没有被显式初始化。在某些特定条件下,这个未初始化的 flags 可能包含 PIPE_BUF_FLAG_CAN_MERGE,导致后续写入时,内核允许将数据合并写入到一个本不该可写的 page cache 页中

利用路径大致是:

  1. 打开一个只读文件
  2. 构造 pipe,使 pipe buffer 的 flags 处于 "可合并" 状态(利用未初始化内存)
  3. 通过 splice/sendfile 等机制,让 pipe buffer 指向只读文件的 page cache
  4. 向 pipe 写入数据 → 数据被合并写入 page cache → 只读文件被修改

影响

  • 影响 Linux kernel 5.8 到 5.16.11 / 5.15.25 / 5.10.102 之间的版本
  • 可写入只读文件 → 直接提权(修改 /etc/passwd 等)
  • PoC 公开后迅速被武器化

为什么它值得记住

Dirty Pipe 是 Dirty COW 之后最 "出圈" 的内核漏洞。它最令人惊讶的地方在于:pipe 是一个非常古老、非常基础的机制,而漏洞原因本质上是一个初始化遗漏——这种 "低级错误" 在现代内核中本不该发生。这说明:即便 Linux kernel 已经极其成熟,复杂性的增加仍然在不断创造新的攻击面。 (国家漏洞数据库)


如果只挑最值得记住的几件,我的选择是:ext4 数据丢失风波(可靠性事故的典型)、Dirty COW(最经典的本地提权)、Meltdown/Spectre(内核为硬件漏洞买单)、Dirty Pipe(现代内核仍有边界穿透)。它们分别代表了内核安全与可靠性的四个不同维度。

Dirty Frag 提权漏洞 [2026-05-09]

Linux 又爆 Dirty Frag 漏洞:Ubuntu、Debian、Arch、RHEL、WSL2 全中招 - 大家的板块 / 青蛙的应用 - 小众软件官方论坛