2026 年 5 月 30 日,Linux 内核社区正式发布 CVE-2026-46242(代号 "Bad Epoll")的修复补丁。这是一个潜伏近三年的 Use-After-Free 竞态条件漏洞,位于 epoll 子系统的
ep_remove()函数中,影响所有基于 Linux 6.4+ 内核的服务器、桌面与 Android 设备。漏洞由首尔国立大学 CompSec Lab 的博士研究员 Jaeyoung Chung 在 2026 年 2 月 17 日报告,公开 PoC 在 kernelCTF 环境(lts-6.12.67 / COS 121-18867.294.100)上实现约 99% 成功率的本地提权到 root。更值得警惕的是:Anthropic 的 Mythos AI 模型此前在同一代码段发现了 CVE-2026-43074 并完成修复,却完全错过了 Bad Epoll------竞态窗口仅约 6 条指令宽,KASAN 不触发,日志几乎无信号。本文从根因、攻击链、检测、修复到内核热补丁与云多租户加固,提供完整实战指南。
1. 漏洞全景概览
1.1 漏洞速览
| 项目 | 详情 |
|---|---|
| CVE 编号 | CVE-2026-46242 |
| 漏洞代号 | Bad Epoll |
| 漏洞类型 | Use-After-Free(竞态条件,CWE-416 / CWE-362) |
| CVSS v3.1 | 7.8(High,本地提权到 root) |
| CVSS 向量 | AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| 影响组件 | Linux 内核 epoll 子系统 fs/eventpoll.c 的 ep_remove() |
| 引入 commit | 58c9b016e128(2023 年 4 月,Linux 6.4 epoll 锁竞争优化) |
| 修复 commit | a6dc643c6931 |
| 发现者 | Jaeyoung Chung(首尔国立大学 CompSec Lab 博士研究员) |
| 报告时间 | 2026 年 2 月 17 日 |
| CVE 发布 | 2026 年 5 月 30 日 |
| PoC 状态 | 已公开(GitHub: J-jaeyoung/bad-epoll),约 99% 成功率获得 root |
| 攻击向量 | 本地(无需特殊权限,普通用户即可) |
| 运行时缓解 | ❌ 无(无法通过配置禁用 epoll,必须打补丁 + 重启或热补丁) |
| 影响版本 | Linux 6.4 → 6.18.32、6.19 → 7.0.9(含 Android 6.6 系列内核) |
| 修复版本 | 6.18.33、7.0.10、7.1-rc1+ |
1.2 Bad Epoll 与 CVE-2026-43074 关联(AI 发现 vs 人工发现)
Bad Epoll 最具警示意义的一段故事,是它与 CVE-2026-43074 的"邻居关系"。两个漏洞位于同一份 fs/eventpoll.c 文件、同一轮 epoll 锁竞争优化引入的代码段,但发现路径截然不同。
#mermaid-svg-jDbQ7Y6gVa3vqZPY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .error-icon{fill:#552222;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .marker.cross{stroke:#333333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY p{margin:0;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .cluster-label text{fill:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .cluster-label span{color:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .cluster-label span p{background-color:transparent;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .label text,#mermaid-svg-jDbQ7Y6gVa3vqZPY span{fill:#333;color:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .node rect,#mermaid-svg-jDbQ7Y6gVa3vqZPY .node circle,#mermaid-svg-jDbQ7Y6gVa3vqZPY .node ellipse,#mermaid-svg-jDbQ7Y6gVa3vqZPY .node polygon,#mermaid-svg-jDbQ7Y6gVa3vqZPY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .rough-node .label text,#mermaid-svg-jDbQ7Y6gVa3vqZPY .node .label text,#mermaid-svg-jDbQ7Y6gVa3vqZPY .image-shape .label,#mermaid-svg-jDbQ7Y6gVa3vqZPY .icon-shape .label{text-anchor:middle;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .rough-node .label,#mermaid-svg-jDbQ7Y6gVa3vqZPY .node .label,#mermaid-svg-jDbQ7Y6gVa3vqZPY .image-shape .label,#mermaid-svg-jDbQ7Y6gVa3vqZPY .icon-shape .label{text-align:center;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .node.clickable{cursor:pointer;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .arrowheadPath{fill:#333333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jDbQ7Y6gVa3vqZPY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jDbQ7Y6gVa3vqZPY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jDbQ7Y6gVa3vqZPY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .cluster text{fill:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .cluster span{color:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jDbQ7Y6gVa3vqZPY rect.text{fill:none;stroke-width:0;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .icon-shape,#mermaid-svg-jDbQ7Y6gVa3vqZPY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .icon-shape p,#mermaid-svg-jDbQ7Y6gVa3vqZPY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .icon-shape .label rect,#mermaid-svg-jDbQ7Y6gVa3vqZPY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jDbQ7Y6gVa3vqZPY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jDbQ7Y6gVa3vqZPY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jDbQ7Y6gVa3vqZPY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 2023年4月
commit 58c9b016e128
epoll锁优化
引入两处缺陷
CVE-2026-43074
Mythos AI发现
CVE-2026-46242 Bad Epoll
Jaeyoung Chung人工发现
Mythos完成修复
2026年初
Mythos再次审计同代码段
❌ 未发现Bad Epoll
2026-02-17
Chung人工代码审查发现
2026-05-30
修复发布CVE-2026-46242
关键启示 :Mythos AI 在发现并修复 CVE-2026-43074 后,再次审计同一代码段,但完全错过了 Bad Epoll。原因是该漏洞的竞态窗口极窄(约 6 条指令),KASAN 因 struct file 标记为 SLAB_TYPESAFE_BY_RCU 而无法触发告警,运行时日志几乎不留痕迹。Chung 通过人工代码审查发现该问题------这给"AI 代码审计可替代人工"的乐观论断敲了一记警钟。
1.3 漏洞核心特征
#mermaid-svg-Op7TvzpSqzbCZIin{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Op7TvzpSqzbCZIin .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Op7TvzpSqzbCZIin .error-icon{fill:#552222;}#mermaid-svg-Op7TvzpSqzbCZIin .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Op7TvzpSqzbCZIin .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Op7TvzpSqzbCZIin .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Op7TvzpSqzbCZIin .marker.cross{stroke:#333333;}#mermaid-svg-Op7TvzpSqzbCZIin svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Op7TvzpSqzbCZIin p{margin:0;}#mermaid-svg-Op7TvzpSqzbCZIin .edge{stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .section--1 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section--1 path,#mermaid-svg-Op7TvzpSqzbCZIin .section--1 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section--1 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section--1 text{fill:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth--1{stroke-width:17;}#mermaid-svg-Op7TvzpSqzbCZIin .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-0 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-0 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-0 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-0 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-0 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-0{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-0{stroke-width:14;}#mermaid-svg-Op7TvzpSqzbCZIin .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-1 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-1 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-1 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-1 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-1 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-1{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-1{stroke-width:11;}#mermaid-svg-Op7TvzpSqzbCZIin .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-2 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-2 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-2 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-2 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-2 text{fill:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-2{stroke-width:8;}#mermaid-svg-Op7TvzpSqzbCZIin .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-3 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-3 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-3 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-3 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-3 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-3{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-3{stroke-width:5;}#mermaid-svg-Op7TvzpSqzbCZIin .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-4 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-4 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-4 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-4 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-4 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-4{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-4{stroke-width:2;}#mermaid-svg-Op7TvzpSqzbCZIin .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-5 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-5 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-5 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-5 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-5 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-5{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-5{stroke-width:-1;}#mermaid-svg-Op7TvzpSqzbCZIin .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-6 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-6 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-6 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-6 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-6 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-6{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-6{stroke-width:-4;}#mermaid-svg-Op7TvzpSqzbCZIin .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-7 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-7 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-7 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-7 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-7 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-7{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-7{stroke-width:-7;}#mermaid-svg-Op7TvzpSqzbCZIin .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-8 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-8 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-8 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-8 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-8 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-8{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-8{stroke-width:-10;}#mermaid-svg-Op7TvzpSqzbCZIin .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-9 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-9 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-9 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-9 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-9 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-9{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-9{stroke-width:-13;}#mermaid-svg-Op7TvzpSqzbCZIin .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-10 rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-10 path,#mermaid-svg-Op7TvzpSqzbCZIin .section-10 circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-10 polygon,#mermaid-svg-Op7TvzpSqzbCZIin .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-10 text{fill:black;}#mermaid-svg-Op7TvzpSqzbCZIin .node-icon-10{font-size:40px;color:black;}#mermaid-svg-Op7TvzpSqzbCZIin .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .edge-depth-10{stroke-width:-16;}#mermaid-svg-Op7TvzpSqzbCZIin .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled,#mermaid-svg-Op7TvzpSqzbCZIin .disabled circle,#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:lightgray;}#mermaid-svg-Op7TvzpSqzbCZIin .disabled text{fill:#efefef;}#mermaid-svg-Op7TvzpSqzbCZIin .section-root rect,#mermaid-svg-Op7TvzpSqzbCZIin .section-root path,#mermaid-svg-Op7TvzpSqzbCZIin .section-root circle,#mermaid-svg-Op7TvzpSqzbCZIin .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-Op7TvzpSqzbCZIin .section-root text{fill:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .section-root span{color:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .section-2 span{color:#ffffff;}#mermaid-svg-Op7TvzpSqzbCZIin .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-Op7TvzpSqzbCZIin .edge{fill:none;}#mermaid-svg-Op7TvzpSqzbCZIin .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-Op7TvzpSqzbCZIin :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CVE-2026-46242
Bad Epoll
漏洞特征
Use-After-Free竞态条件
仅6条指令竞态窗口
本地提权到root
99%可靠利用成功率
潜伏近三年2023-2026
技术原理
ep_remove清file.f_ep后继续用file
并发__fput走快速路径跳过同步
eventpoll对象被提前kfree
hlist_del_rcu写入已释放kmalloc-192
SLAB_TYPESAFE_BY_RCU掩盖KASAN
影响范围
Linux 6.4+全系列
Android 6.6内核设备
Pixel 8的6.1内核不受影响
云多租户共享内核
Chrome渲染器沙箱可链式逃逸
修复方案
epi_fget钉住struct file
无运行时缓解必须打补丁
内核热补丁kpatch/livepatch
升级到6.18.33或7.0.10+
云环境滚动重启宿主机
2. 漏洞根因深度分析
2.1 epoll 子系统背景知识
epoll 是 Linux 内核提供的高性能 I/O 多路复用机制,自 Linux 2.5.44 引入以来,已成为 Nginx、Redis、Node.js、Python asyncio、几乎所有数据库引擎和容器运行时的事件驱动基石。其核心优势在于:事件通知采用回调驱动而非轮询,时间复杂度从 O(n) 降至 O(1),可高效管理数十万并发连接。
epoll 的三个核心系统调用构成完整生命周期:
epoll_create1(flags):创建 epoll 实例,内核分配struct eventpoll,返回文件描述符。该 fd 本身也是一个struct file,因此 epoll 实例可以被另一个 epoll 实例监视(嵌套 epoll)。epoll_ctl(epfd, op, fd, event):向 epoll 实例添加/修改/删除被监视的 fd,核心操作是将fd与对应的struct epitem插入红黑树或从中移除。epoll_wait(epfd, events, maxevents, timeout):阻塞等待事件就绪,内核检查就绪链表,事件到达时唤醒等待进程。
关键点 :epoll 实例本身是 struct file,可以被另一个 epoll 监视。这条"epoll 监视 epoll"的嵌套路径,正是 Bad Epoll 漏洞的利用通道。
epoll 子系统的核心实现在 fs/eventpoll.c 中。struct eventpoll 通过 kmem_cache 分配,属于 kmalloc-192 slab(取决于内核版本和编译配置)。struct file 则标记为 SLAB_TYPESAFE_BY_RCU------这个标记是后续 KASAN 失灵的关键。
2.2 ep_remove() UAF 根因分析
漏洞位于 ep_remove() 函数(通过 ep_remove_file() 调用)。问题代码的简化逻辑如下:
c
// 漏洞版本简化示意 --- fs/eventpoll.c 中的 ep_remove()
static void ep_remove(struct eventpoll *ep, struct epitem *epi)
{
struct file *file;
ep_unregister_pollwait(ep, epi);
// 步骤1:判断 dying 标志(无锁快速路径)
if (unlikely(READ_ONCE(epi->dying)))
return;
// 步骤2:取 file 指针(⚠️ 未增加引用计数)
file = epi->ffd.file;
// 步骤3:加 file->f_lock 后清除 file->f_ep
spin_lock(&file->f_lock);
// 关键缺陷:清除 f_ep,相当于宣布"该 file 不再被 epoll 监视"
if (ep_cmp_ffd(&epi->ffd, &ep->ffs))
file->f_ep = NULL; // ← 瞬态 NULL 出现
// 步骤4:继续在临界区内使用 file(⚠️ 此时 file 可能已被并发 __fput 释放)
hlist_del_rcu(&epi->fllink); // ← 通过 epi->fllink.pprev 写入
spin_unlock(&file->f_lock);
// 步骤5:后续操作可能解引用已释放的 eventpoll
// ...
}
问题链条的根因可以归纳为以下五步:
ep_remove()在file->f_lock下清除file->f_ep,相当于宣布"该 file 不再被 epoll 监视"。- 但函数继续在临界区内通过
hlist_del_rcu()和spin_unlock()使用同一个file对象。 - 与此同时,另一个线程执行
__fput()(关闭文件描述符的内核路径)。 __fput()观察到file->f_ep == NULL这个瞬态值,认为该 file 不再被任何 epoll 监视,于是跳过eventpoll_release_file()的同步慢路径 ,直接走快速路径进入f_op->release()与file_free()。- 对于 epoll 监视 epoll 的嵌套场景,
f_op->release即ep_eventpoll_release()→ep_clear_and_put()→ep_free(),会kfree()掉被监视的struct eventpoll。而该 eventpoll 内嵌的->refshlist_head 正是epi->fllink.pprev指向的位置------后续hlist_del_rcu()的*pprev = next写操作,就写入了已释放的 kmalloc-192 内存。
更严重的是,由于 struct file 标记为 SLAB_TYPESAFE_BY_RCU,该 slab 槽位可能在 ep_remove() 仍"持有" f_lock 期间被 alloc_empty_file() 回收并重新初始化(包括 f_lock 和 f_ep)。最终结果是攻击者可控的 kmem_cache_free() 被导向错误的 slab cache------一个完整的 UAF 原语。
2.3 竞态窗口分析(6 条指令)
竞态窗口的"窄"是 Bad Epoll 最具迷惑性的特征。整个竞态区域仅约 6 条指令宽:
text
CPU 0 (ep_remove 上下文) CPU 1 (__fput 上下文)
───────────────────────── ─────────────────────────
spin_lock(&file->f_lock)
file->f_ep = NULL ←──窗口──→ READ file->f_ep (观察到 NULL)
跳过 eventpoll_release_file()
f_op->release() → ep_free()
hlist_del_rcu(&epi->fllink) kfree(eventpoll) ← 已释放
*pprev = next ← 写入已释放内存 (slot 可能已被回收重用)
spin_unlock(&file->f_lock)
为什么 KASAN 抓不到?
KASAN(Kernel Address Sanitizer)是检测 UAF 的常规武器,但这里失效了,原因有二:
struct file标记为SLAB_TYPESAFE_BY_RCU,KASAN 默认不对其隔离 quarantine,slab 槽位可被合法回收重用,KASAN 无法识别为"已释放"。eventpoll被kfree()后,其内嵌的refshlist_head 内存被回收,但epi->fllink.pprev仍指向该位置,写入时若 slot 已被新对象重用,KASAN 看到的是"活跃对象"而非"已释放对象"。
为什么 AI 审计错过了?
Anthropic 的 Mythos AI 模型在发现 CVE-2026-43074 后再次审计同一代码段,未能识别 Bad Epoll。综合公开分析,原因包括:
- 竞态窗口太窄,AI 倾向于在显式锁顺序、明显空指针解引用等"静态信号"上识别问题。
- 漏洞依赖
SLAB_TYPESAFE_BY_RCU这种"看似安全"的标记来掩盖,AI 难以将 slab 标记与并发释放语义关联起来。 - 运行时无 KASAN 告警、无崩溃日志,AI 在缺乏运行时证据时倾向于"代码看起来正确"。
Chung 通过人工逐行代码审查 ,结合对 __fput() 快速路径与 ep_remove() 临界区交叉语义的深度推演,才识别出这个 6 指令窗口。
3. 攻击链分析
3.1 攻击前置条件
| 条件 | 说明 |
|---|---|
| 本地代码执行 | 攻击者需在目标主机上拥有普通用户 shell(无 root 权限) |
| 内核版本 | Linux 6.4+ 未打补丁内核(含 Android 6.6 系列) |
| 特殊权限 | ❌ 无需任何特殊权限,普通用户即可 |
| 用户交互 | ❌ 无需用户交互 |
| 网络要求 | ❌ 纯本地漏洞,无需网络访问 |
| 云多租户场景 | 共享内核的云环境,任何租户获得本地 shell 即可尝试触达宿主机 |
| 容器场景 | 容器内普通用户即可触发,容器与宿主机共享内核 |
3.2 完整利用链
#mermaid-svg-kUeCooKhZlk6BFaz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kUeCooKhZlk6BFaz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kUeCooKhZlk6BFaz .error-icon{fill:#552222;}#mermaid-svg-kUeCooKhZlk6BFaz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kUeCooKhZlk6BFaz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kUeCooKhZlk6BFaz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kUeCooKhZlk6BFaz .marker.cross{stroke:#333333;}#mermaid-svg-kUeCooKhZlk6BFaz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kUeCooKhZlk6BFaz p{margin:0;}#mermaid-svg-kUeCooKhZlk6BFaz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kUeCooKhZlk6BFaz .cluster-label text{fill:#333;}#mermaid-svg-kUeCooKhZlk6BFaz .cluster-label span{color:#333;}#mermaid-svg-kUeCooKhZlk6BFaz .cluster-label span p{background-color:transparent;}#mermaid-svg-kUeCooKhZlk6BFaz .label text,#mermaid-svg-kUeCooKhZlk6BFaz span{fill:#333;color:#333;}#mermaid-svg-kUeCooKhZlk6BFaz .node rect,#mermaid-svg-kUeCooKhZlk6BFaz .node circle,#mermaid-svg-kUeCooKhZlk6BFaz .node ellipse,#mermaid-svg-kUeCooKhZlk6BFaz .node polygon,#mermaid-svg-kUeCooKhZlk6BFaz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kUeCooKhZlk6BFaz .rough-node .label text,#mermaid-svg-kUeCooKhZlk6BFaz .node .label text,#mermaid-svg-kUeCooKhZlk6BFaz .image-shape .label,#mermaid-svg-kUeCooKhZlk6BFaz .icon-shape .label{text-anchor:middle;}#mermaid-svg-kUeCooKhZlk6BFaz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kUeCooKhZlk6BFaz .rough-node .label,#mermaid-svg-kUeCooKhZlk6BFaz .node .label,#mermaid-svg-kUeCooKhZlk6BFaz .image-shape .label,#mermaid-svg-kUeCooKhZlk6BFaz .icon-shape .label{text-align:center;}#mermaid-svg-kUeCooKhZlk6BFaz .node.clickable{cursor:pointer;}#mermaid-svg-kUeCooKhZlk6BFaz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kUeCooKhZlk6BFaz .arrowheadPath{fill:#333333;}#mermaid-svg-kUeCooKhZlk6BFaz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kUeCooKhZlk6BFaz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kUeCooKhZlk6BFaz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kUeCooKhZlk6BFaz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kUeCooKhZlk6BFaz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kUeCooKhZlk6BFaz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kUeCooKhZlk6BFaz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kUeCooKhZlk6BFaz .cluster text{fill:#333;}#mermaid-svg-kUeCooKhZlk6BFaz .cluster span{color:#333;}#mermaid-svg-kUeCooKhZlk6BFaz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kUeCooKhZlk6BFaz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kUeCooKhZlk6BFaz rect.text{fill:none;stroke-width:0;}#mermaid-svg-kUeCooKhZlk6BFaz .icon-shape,#mermaid-svg-kUeCooKhZlk6BFaz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kUeCooKhZlk6BFaz .icon-shape p,#mermaid-svg-kUeCooKhZlk6BFaz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kUeCooKhZlk6BFaz .icon-shape .label rect,#mermaid-svg-kUeCooKhZlk6BFaz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kUeCooKhZlk6BFaz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kUeCooKhZlk6BFaz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kUeCooKhZlk6BFaz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 攻击者获得本地普通用户shell
创建4个epoll文件描述符
epfd0 → epfd1 → epfd2 → epfd3
形成嵌套监视链
利用prefetch侧信道
泄露KASLR基址
触发ep_remove竞态
通过精心构造的关闭顺序
竞态命中
eventpoll被kfree
Cross-Cache喷涂
用pipe缓冲区回收kmalloc-192 slot
通过/proc/self/fdinfo
读取任意内核内存
定位当前进程cred结构
构造ROP链
stack pivot到可控内存
覆盖cred->uid/gid为0
获得root权限
返回用户态
弹出root shell
公开 PoC 的核心技术亮点(基于原理分析与公开 writeup 整理):
1. KASLR 绕过(prefetch 侧信道)
text
利用原理:
- epoll 嵌套监视会在内核侧形成 epitem 链表
- 通过 prefetch 指令探测内核地址是否映射
- 结合 /proc/self/fdinfo 暴露的内核指针
- 反推内核 .text 段基址,绕过 KASLR
2. 拓宽 6 指令竞态窗口
text
竞态拓宽手法:
- 通过 CPU 亲和性绑定将两个线程钉在不同 CPU 核
- 利用 userfaultfd 或 FUSE 暂停一个线程
- 通过 cache 预取误导 CPU 流水线
- 将 6 指令窗口实际拓宽到可稳定命中
3. Race-Win Oracle(竞态命中判别)
公开 writeup 描述了一个巧妙的"竞态命中判别器"------通过观察 /proc/self/fdinfo 的输出变化判断竞态是否命中,避免盲目重试。这是将 99% 可靠性的关键工程突破。
4. Cross-Cache 喷涂与 pipe 回收
text
内存回收原语:
- eventpoll 属于 kmalloc-192 slab
- 触发 kfree 后,立即用 pipe 缓冲区喷射同大小对象
- pipe_buffer 恰好可落入回收的 slot
- 通过 /proc/self/fdinfo 读取 pipe_buffer 内容 = 任意内核内存读
5. RIP 控制与 stack pivot
通过任意读定位当前进程 cred 结构后,构造 ROP 链覆盖 cred->uid/gid 为 0,完成提权。公开 PoC 报告在 kernelCTF lts-6.12.67 上约 99% 成功,在 COS 121-18867.294.100 上约 98% 成功。
3.3 云多租户横向移动风险
Bad Epoll 对云环境的威胁远超传统本地提权。在共享内核的云环境(如传统容器、某些 serverless 平台)中,最坏情况是任何租户获得 root 后可能触达宿主机。
#mermaid-svg-7VAFIQp5hGY30Zyf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7VAFIQp5hGY30Zyf .error-icon{fill:#552222;}#mermaid-svg-7VAFIQp5hGY30Zyf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7VAFIQp5hGY30Zyf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7VAFIQp5hGY30Zyf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7VAFIQp5hGY30Zyf .marker.cross{stroke:#333333;}#mermaid-svg-7VAFIQp5hGY30Zyf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7VAFIQp5hGY30Zyf p{margin:0;}#mermaid-svg-7VAFIQp5hGY30Zyf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf .cluster-label text{fill:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf .cluster-label span{color:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf .cluster-label span p{background-color:transparent;}#mermaid-svg-7VAFIQp5hGY30Zyf .label text,#mermaid-svg-7VAFIQp5hGY30Zyf span{fill:#333;color:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf .node rect,#mermaid-svg-7VAFIQp5hGY30Zyf .node circle,#mermaid-svg-7VAFIQp5hGY30Zyf .node ellipse,#mermaid-svg-7VAFIQp5hGY30Zyf .node polygon,#mermaid-svg-7VAFIQp5hGY30Zyf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7VAFIQp5hGY30Zyf .rough-node .label text,#mermaid-svg-7VAFIQp5hGY30Zyf .node .label text,#mermaid-svg-7VAFIQp5hGY30Zyf .image-shape .label,#mermaid-svg-7VAFIQp5hGY30Zyf .icon-shape .label{text-anchor:middle;}#mermaid-svg-7VAFIQp5hGY30Zyf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7VAFIQp5hGY30Zyf .rough-node .label,#mermaid-svg-7VAFIQp5hGY30Zyf .node .label,#mermaid-svg-7VAFIQp5hGY30Zyf .image-shape .label,#mermaid-svg-7VAFIQp5hGY30Zyf .icon-shape .label{text-align:center;}#mermaid-svg-7VAFIQp5hGY30Zyf .node.clickable{cursor:pointer;}#mermaid-svg-7VAFIQp5hGY30Zyf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7VAFIQp5hGY30Zyf .arrowheadPath{fill:#333333;}#mermaid-svg-7VAFIQp5hGY30Zyf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7VAFIQp5hGY30Zyf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7VAFIQp5hGY30Zyf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7VAFIQp5hGY30Zyf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7VAFIQp5hGY30Zyf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7VAFIQp5hGY30Zyf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7VAFIQp5hGY30Zyf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7VAFIQp5hGY30Zyf .cluster text{fill:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf .cluster span{color:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7VAFIQp5hGY30Zyf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7VAFIQp5hGY30Zyf rect.text{fill:none;stroke-width:0;}#mermaid-svg-7VAFIQp5hGY30Zyf .icon-shape,#mermaid-svg-7VAFIQp5hGY30Zyf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7VAFIQp5hGY30Zyf .icon-shape p,#mermaid-svg-7VAFIQp5hGY30Zyf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7VAFIQp5hGY30Zyf .icon-shape .label rect,#mermaid-svg-7VAFIQp5hGY30Zyf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7VAFIQp5hGY30Zyf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7VAFIQp5hGY30Zyf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7VAFIQp5hGY30Zyf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 云租户A
普通用户shell
利用Bad Epoll
容器内提权到root
容器root权限
利用其他内核漏洞
或容器逃逸技术
触达宿主机内核
宿主机root权限
横扫同宿主机所有租户
访问宿主机元数据服务
窃取云凭证
攻击云控制平面
云租户B
隔离被打破
云租户C
隔离被打破
关键风险点:
- 共享内核 = 共享攻击面:传统容器(Docker、containerd 默认配置)与宿主机共享内核,内核漏洞等于全员漏洞。
- 沙箱逃逸跳板:Bad Epoll 把"容器内普通用户"提升到"容器内 root",这是后续容器逃逸(如 CVE-2024-21626 runc、CVE-2022-0185 filesystem context)的标准跳板。
- serverless 冷启动风险:某些 serverless 平台在共享内核上运行用户代码,攻击者可在冷启动窗口内尝试利用。
- CI/CD 流水线投毒:恶意 npm/PyPI/Maven 包在 CI runner 上获得本地 shell → Bad Epoll 提权 → 窃取 CI 凭证 → 投毒下游构建产物。
3.4 Chrome 渲染器沙箱逃逸角度
据公开报道,Bad Epoll 还可从 Chrome 渲染器沙箱内触发。Chrome 渲染器沙箱虽然限制了文件系统访问,但渲染器进程仍可调用 epoll 系统调用(用于网络事件循环)。攻击链如下:
text
攻击链(基于原理分析):
1. 攻击者通过恶意网页触发 Chrome 渲染器漏洞(如 V8 类型混淆)
2. 在渲染器进程内获得代码执行(受沙箱限制)
3. 利用渲染器可访问的 epoll 系统调用触发 Bad Epoll
4. 从渲染器进程内提权到内核 root
5. 沙箱彻底失效,可访问用户数据、其他进程内存
这条路径使 Bad Epoll 与其他内核漏洞可以链式利用,从"打开恶意网页"一路到"完全控制用户系统",威胁等级显著上升。
4. 检测与诊断
4.1 受影响版本排查(uname -r)
Bad Epoll 的修复依赖于具体内核版本号,第一步必须盘点环境中所有 Linux 主机的内核版本。
bash
# 检查当前内核版本
uname -r
# 预期输出(受影响示例): 6.8.0-45-generic
# 预期输出(已修复示例): 6.18.33-060118-generic
# 查看所有已安装内核(Debian/Ubuntu)
dpkg --list | grep -E "linux-image-[0-9]"
# 预期输出:
# ii linux-image-6.8.0-45-generic 6.8.0-45.45~22.04.1 amd64 Linux kernel image for version 6.8.0 on 64 bit x86 SMP
# ii linux-image-6.8.0-50-generic 6.8.0-50.50~22.04.1 amd64 Linux kernel image for version 6.8.0 on 64 bit x86 SMP
# 查看 RHEL/Rocky/AlmaLinux 已安装内核
rpm -qa | grep -E "^kernel-[0-9]"
# 预期输出:
# kernel-6.8.0-55.55.el9_4.x86_64
版本判定逻辑(基于公开 metadata 整理):
| 内核版本区间 | 状态 |
|---|---|
< 5.16(如 5.15.209) |
✅ 不受影响 |
5.16 → 6.1.174 |
✅ 不受影响(5.16 之前未引入) |
6.1.175 → 6.1.x(部分 backport) |
⚠️ 需查 vendor advisory |
6.2 → 6.3.x |
✅ 不受影响 |
6.4 → 6.18.32 |
🔴 受影响 |
6.18.33+ |
✅ 已修复 |
6.19 → 7.0.9 |
🔴 受影响 |
7.0.10+ |
✅ 已修复 |
7.1-rc1+ |
✅ 已修复 |
4.2 各发行版补丁状态检查
发行版内核版本号与上游版本号不一致,必须以 vendor advisory 为准。
bash
# Ubuntu 检查(含 HWE 内核)
ubuntu-security-status --unresolved
# 或更精确地查询 CVE 状态
pro security-status --cve CVE-2026-46242
# 预期输出(受影响):
# CVE-2026-46242: vulnerable (linux 6.8.0-45.45~22.04.1)
# 预期输出(已修复):
# CVE-2026-46242: not affected (linux 7.0.0-28.28)
# RHEL/Rocky/AlmaLinux 检查
yum updateinfo list --cves CVE-2026-46242
# 或
dnf updateinfo list --cves CVE-2026-46242
# 预期输出(有可用补丁):
# RHSA-2026:XXXX Important/Sec. kernel-6.8.0-55.55.el9_4.x86_64
# SUSE/openSUSE 检查
zypper list-patches --cve CVE-2026-46242
# Debian 检查
apt-list --cve CVE-2026-46242 2>/dev/null || \
grep CVE-2026-46242 /usr/share/debian-security-support/security-support-ended 2>/dev/null
主要发行版状态速查(截至 2026 年 7 月,基于 Ubuntu/Corgea 公开数据):
| 发行版 | 版本 | 状态 |
|---|---|---|
| Ubuntu 26.04 LTS (resolute) | linux 7.0.0-28.28 | ✅ Fixed |
| Ubuntu 24.04 LTS (noble) | linux | ⚠️ Vulnerable, work in progress |
| Ubuntu 22.04 LTS (jammy) | linux | ✅ Not affected |
| Ubuntu 22.04 + HWE-6.8 | linux-hwe-6.8 | 🔴 Vulnerable |
| Ubuntu 20.04 LTS (focal) | linux | ✅ Not affected |
| RHEL 9 / Rocky 9 / Alma 9 | kernel 6.8.x | ⚠️ 检查 RHSA |
| Android 6.6 系列 | 6.6.x | 🔴 受影响(Pixel 8 的 6.1 不受影响) |
4.3 异常 futex/epoll 系统调用检测
Bad Epoll 攻击会在短时间内产生大量 epoll_create/epoll_ctl/close 系统调用模式,可作为检测信号。
bash
# 使用 perf 监控 epoll 系统调用异常
sudo perf stat -e 'syscalls:sys_enter_epoll_create*' \
-e 'syscalls:sys_enter_epoll_ctl' \
-e 'syscalls:sys_enter_close' \
-a -- sleep 60
# 使用 bpftrace 检测高频 epoll 嵌套(可疑模式)
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_epoll_ctl
/comm != "nginx" && comm != "redis-server" && comm != "node"/ {
@[comm, pid] = count();
}
interval:s:60 { print(@); clear(@); }
'
# 检测 /proc/self/fdinfo 异常读取(PoC 利用特征)
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_openat
/str(args->filename) == "/proc/self/fdinfo"/ {
printf("suspicious fdinfo read by %s pid=%d\n", comm, pid);
}
'
注意:上述检测为"信号"而非"阻断"------Bad Epoll 利用窗口极短,运行时检测无法阻止提权,只能用于事后取证。真正的防护必须依赖补丁。
5. 修复方案
5.1 内核升级(各发行版)
升级到修复版本是最彻底的方案。Bad Epoll 无运行时缓解,补丁是唯一根治手段。
Ubuntu/Debian 升级:
bash
# 更新软件包索引
sudo apt update
# 安装修复版内核(以 Ubuntu 26.04 为例)
sudo apt install --only-upgrade linux-image-generic linux-headers-generic
# 预期输出:
# Setting up linux-image-7.0.0-28-generic (7.0.0-28.28) ...
# Setting up linux-headers-7.0.0-28-generic (7.0.0-28.28) ...
# 验证新内核已安装
ls /boot/vmlinuz-*
# 预期输出: /boot/vmlinuz-7.0.0-28-generic
# 重启生效(⚠️ 必须重启,无运行时缓解)
sudo reboot
# 重启后验证
uname -r
# 预期输出: 6.18.33-060118-generic 或更高
RHEL/Rocky/AlmaLinux 升级:
bash
# 更新内核到修复版本
sudo dnf update kernel kernel-core kernel-modules
# 预期输出:
# Upgrading:
# kernel-core x86_64 6.18.33-100.el9 rhel-9-baseos 45 M
# kernel-modules x86_64 6.18.33-100.el9 rhel-9-baseos 12 M
# 重启生效
sudo reboot
# 验证
uname -r
Android 设备:等待设备厂商推送安全补丁。Pixel 8(6.1 内核)不受影响;Pixel 9/10 及其他搭载 6.6 内核的设备需关注厂商公告。
5.2 内核热补丁(kpatch / livepatch / kGraft)
对无法容忍重启的云宿主机、数据库节点、K8s control plane,内核热补丁是"无停机修复"的关键能力。Bad Epoll 漏洞函数
ep_remove()调用路径相对独立,热补丁可行性较好。
Ubuntu Livepatch(Canonical Livepatch Service):
bash
# 启用 Canonical Livepatch(需 Ubuntu Pro 订阅,个人用户免费)
sudo pro attach ${UBUNTU_PRO_TOKEN}
sudo pro enable livepatch
# 检查 livepatch 状态
canonical-livepatch status
# 预期输出:
# kernel: 6.8.0-45-generic
# fully-patched: true
# patches:
# CVE-2026-46242 (Bad Epoll): applied
# 应用特定补丁
sudo canonical-livepatch refresh
RHEL Kernel Live Patching(kpatch):
bash
# 安装 kpatch 工具
sudo dnf install kpatch kpatch-dnf
# 订阅并启用
sudo dnf copr enable @kernel/livepatch
sudo dnf install "kernel-livepatch-*"
# 查看已应用补丁
sudo kpatch list
# 预期输出:
# Loaded patch modules:
# livepatch_ep_remove_fix [enabled]
# 应用补丁
sudo kpatch load livepatch_ep_remove_fix.ko
# 验证补丁生效(无需重启)
sudo kpatch info livepatch_ep_remove_fix.ko
SUSE kGraft:
bash
# SUSE/openSUSE 热补丁
sudo zypper install kgraft
sudo zypper install kgraft-patch-*=CVE-2026-46242
# 查看已加载热补丁
sudo kgraft list
热补丁适用性判断:
| 场景 | 是否推荐热补丁 | 说明 |
|---|---|---|
| 云宿主机(KVM hypervisor) | ✅ 强烈推荐 | 避免影响所有租户 VM |
| K8s control plane 节点 | ✅ 推荐 | 避免控制面抖动 |
| 数据库主节点 | ✅ 推荐 | 避免连接中断 |
| 普通 Web 服务器 | ⚠️ 可选 | 维护窗口重启更彻底 |
| Android 设备 | ❌ 不适用 | 等待厂商 OTA |
| 已运行 PoC 的环境 | ❌ 不适用 | 必须重启 + 全盘取证 |
重要约束:热补丁只是"临时止血",仍需在下一个维护窗口安排完整重启。建议热补丁 + 30 天内重启为标准流程。
5.3 云环境加固
云多租户场景下,Bad Epoll 的攻击半径从"单机提权"扩大到"宿主机沦陷 → 全租户沦陷"。加固必须从宿主机内核与租户隔离两层入手。
yaml
# K8s Pod Security Standards 加固示例
apiVersion: v1
kind: Namespace
metadata:
name: untrusted-tenant
labels:
# 强制 enforce restricted 模式
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
apiVersion: v1
kind: Pod
metadata:
name: hardened-app
namespace: untrusted-tenant
spec:
securityContext:
# 必须以非 root 运行
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
# 禁止特权提升
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: ${APP_IMAGE}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
memory: 512Mi
cpu: 500m
gVisor / Kata Containers 隔离:
bash
# 对高敏感租户使用 gVisor(用户态内核,拦截 syscall)
# Containerd 配置 /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.gvisor]
runtime_type = "io.containerd.runsc.v1"
privileged_without_host_devices = false
# RuntimeClass
cat <<EOF | kubectl apply -f -
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
EOF
# Pod 指定使用 gvisor
# spec.runtimeClassName: gvisor
注意:gVisor 在用户态实现 syscall 拦截,可显著缩小内核攻击面(epoll 调用被 gVisor 拦截后不直接触达宿主机内核),但会带来性能开销。Kata Containers 用轻量 VM 隔离每个 Pod,对内核漏洞防护更强,适合高敏感场景。
5.4 安全加固检查清单
markdown
□ 所有 Linux 主机内核是否已升级到 6.18.33+ 或 7.0.10+?
□ 关键宿主机是否已应用内核热补丁(livepatch/kpatch)?
□ 是否已安排 30 天内的完整重启窗口?
□ K8s 集群是否启用 Pod Security Standards restricted 模式?
□ 高敏感租户是否使用 gVisor / Kata Containers 隔离?
□ CI/CD runner 是否在补丁完成前限制外部依赖安装?
□ Android 设备是否已检查厂商安全公告并等待 OTA?
□ 是否部署 epoll 系统调用异常监控(bpftrace/perf)?
□ 是否盘点所有 Ubuntu 22.04 + HWE-6.8 内核(受影响)?
□ 是否建立内核漏洞应急响应流程(PoC 公开后 24h 内)?
6. 踩坑记录
| 序号 | 坑 | 现象 | 根因分析 | 解决方案 | 效果 |
|---|---|---|---|---|---|
| 1 | HWE 内核被忽视 | 主内核已升级,仍被 PoC 提权 | Ubuntu 22.04 默认内核不受影响,但 HWE-6.8 内核受影响,运维只检查了主内核 | 全量盘点 linux-hwe-* 包,HWE 内核单独升级 |
漏洞真正闭合 |
| 2 | livepatch 静默失败 | 状态显示 applied,但 PoC 仍成功 | livepatch 模块加载失败但状态报告滞后,未实际钉住 ep_remove |
kpatch list 二次确认 + dmesg 检查加载日志 |
补丁确实生效 |
| 3 | K8s 滚动升级卡死 | 升级节点内核后节点 NotReady | 节点未 cordon/drain 直接重启,Pod 未能优雅迁移 |
先 kubectl cordon + kubectl drain 再重启 |
零中断升级 |
| 4 | Android 设备漏报 | 厂商称"已修复",实际仍可利用 | 厂商 backport 了部分 patch 但漏掉 epi_fget() 钉住逻辑 |
与厂商确认补丁 commit hash 是否包含 a6dc643c6931 |
真正修复 |
| 5 | 容器内升级无效 | apt upgrade 后 PoC 仍成功 |
容器与宿主机共享内核,容器内升级的内核包不生效 | 必须升级宿主机内核,容器内仅升级用户态工具 | 修复生效 |
| 6 | gVisor 兼容性报错 | 切换 gVisor 后部分 Pod CrashLoopBackOff | gVisor 不支持某些 syscall(如 inotify_add_watch 部分场景) |
高敏感租户用 gVisor,普通租户用 runc + restricted PSA | 兼容与安全平衡 |
坑 1 详解:HWE 内核被忽视
这是 Bad Epoll 修复中最常见的盲区。Ubuntu 22.04 LTS 默认内核 5.15 不受影响,但许多用户为获得新硬件支持或新特性启用了 HWE-6.8 内核。运维在自查时往往只检查 uname -r 看到的是 5.15,但实际运行的是 6.8(HWE),或反之。正确做法是同时检查 linux-image-generic 与 linux-image-hwe-* 两个包:
bash
# 一次性列出所有已安装内核包
dpkg -l | grep -E "^ii\s+linux-image" | awk '{print $2, $3}'
# 预期输出示例:
# linux-image-5.15.0-125-generic 5.15.0-125.135
# linux-image-6.8.0-45-generic 6.8.0-45.45~22.04.1 ← HWE,受影响
坑 2 详解:livepatch 静默失败
内核热补丁在某些场景下会"声称已应用但实际未生效"。canonical-livepatch status 显示 applied,但 ep_remove() 仍是漏洞版本。原因可能是 livepatch 模块加载时 ep_remove 正被占用,patch 跳过了该函数。可靠验证方式:
bash
# 检查 livepatch 实际钉住的函数
sudo cat /sys/kernel/livepatch/*/kallsyms 2>/dev/null | grep ep_remove
# 预期输出(已生效):
# ffffffff813a2b50 t ep_remove [livepatch_cve_2026_46242]
# 检查 dmesg 是否有 patch 失败警告
sudo dmesg | grep -i "livepatch.*fail\|livepatch.*skip"
坑 5 详解:容器内升级无效
容器与宿主机共享内核,这是常识,但在紧急响应中仍频繁踩坑。运维在容器内执行 apt upgrade linux-image-* 后,PoC 仍能成功------因为容器内的内核包根本不会被加载。正确流程:
text
1. 在宿主机上升级内核(不是在容器内)
2. 重启宿主机(或热补丁)
3. 验证容器内 uname -r 与宿主机一致
4. 容器内仅升级用户态工具(如 openssl、curl)不影响内核
📊 运维监控与自动化保障
监控项
| 监控项 | 指标 | 告警阈值 | 检测意义 |
|---|---|---|---|
| 内核版本 | node_uname_info |
< 6.18.33(6.4+ 分支) | 受影响版本持续暴露 |
| livepatch 状态 | node_livepatch_applied |
漏洞补丁未 applied | 热补丁失效 |
| epoll 系统调用速率 | rate(sys_enter_epoll_ctl[5m]) |
单进程 > 1000/s | PoC 利用特征 |
| fdinfo 读取频次 | rate(sys_enter_openat["/proc/self/fdinfo"][5m]) |
单进程 > 50/min | PoC 任意读原语 |
| 进程 uid 异常跃迁 | process_credentials{uid="0"} |
非 sudo 进程 uid 突变 0 | 提权成功信号 |
| 内核 oops 计数 | rate(node_kernel_oops_last[5m]) |
> 0 | 利用失败的副作用 |
| K8s Pod 重启 | kube_pod_container_status_restarts_total |
非预期重启 > 3 | 容器逃逸尝试 |
Prometheus 告警规则
基于 Prometheus + node_exporter 的内核漏洞监控,可在大规模集群中自动发现受影响节点与可疑活动。
yaml
# prometheus-rules-cve-2026-46242.yaml
groups:
- name: cve-2026-46242-bad-epoll
rules:
# 告警1:受影响内核版本
- alert: KernelVulnerableToBadEpoll
expr: |
count by (instance) (
node_uname_info{release=~"6\.(4|5|6|7|8|9|1[0-8])\..*"}
and on(instance)
node_uname_info{release!~"6\.18\.(3[3-9]|[4-9][0-9])\..*"}
) > 0
for: 10m
labels:
severity: critical
cve: CVE-2026-46242
annotations:
summary: "节点内核受 Bad Epoll 漏洞影响"
description: "节点 {{ $labels.instance }} 内核版本 {{ $value }} 受 CVE-2026-46242 影响,需立即升级到 6.18.33+。"
# 告警2:livepatch 未应用
- alert: LivepatchNotAppliedForBadEpoll
expr: |
node_livepatch_state{patch="cve_2026_46242"} != 1
for: 5m
labels:
severity: warning
cve: CVE-2026-46242
annotations:
summary: "Bad Epoll 热补丁未应用"
description: "节点 {{ $labels.instance }} 的 CVE-2026-46242 热补丁未生效。"
# 告警3:可疑 epoll 高频调用
- alert: SuspiciousEpollActivity
expr: |
rate(node_system_calls_total{call="epoll_ctl"}[5m]) > 1000
for: 2m
labels:
severity: warning
annotations:
summary: "检测到高频 epoll_ctl 调用"
description: "节点 {{ $labels.instance }} epoll_ctl 速率 {{ $value }}/s,疑似 Bad Epoll 利用尝试。"
自动化巡检脚本(Python,跨发行版)
跨发行版巡检脚本可在异构环境中统一发现受影响主机,避免逐台手动检查。
python
#!/usr/bin/env python3
# bad_epoll_audit.py --- CVE-2026-46242 跨发行版巡检脚本
# 用法: python3 bad_epoll_audit.py [--ssh-hosts hosts.txt]
# 依赖: 仅使用标准库,无第三方包
import subprocess
import re
import sys
import argparse
from dataclasses import dataclass
from typing import Optional
# 受影响的内核版本区间(基于公开 metadata 整理)
AFFECTED_RANGES = [
# (起始, 结束, 说明)
("6.4.0", "6.18.32", "主线 6.4 - 6.18.32 受影响"),
("6.19.0", "7.0.9", "6.19 - 7.0.9 受影响"),
]
@dataclass
class KernelStatus:
hostname: str
kernel: str
affected: bool
fixed_version: Optional[str]
livepatch_applied: bool
detail: str
def parse_version(ver: str) -> tuple:
"""将版本字符串解析为可比较的元组"""
parts = re.findall(r"\d+", ver.split("-")[0])
return tuple(int(p) for p in parts[:3])
def is_affected(kernel: str) -> tuple:
"""判断内核是否受影响,返回 (受影响, 修复版本)"""
try:
v = parse_version(kernel)
except Exception:
return False, None
for start, end, desc in AFFECTED_RANGES:
s = parse_version(start)
e = parse_version(end)
if s <= v <= e:
# 推荐修复版本
if v < parse_version("6.19.0"):
return True, "6.18.33"
else:
return True, "7.0.10"
return False, None
def check_livepatch() -> bool:
"""检查 livepatch 是否已应用(Ubuntu Livepatch)"""
try:
result = subprocess.run(
["canonical-livepatch", "status"],
capture_output=True, text=True, timeout=10
)
return "CVE-2026-46242" in result.stdout and "applied" in result.stdout
except (FileNotFoundError, subprocess.TimeoutExpired):
return False
def audit_local() -> KernelStatus:
"""审计本地主机"""
hostname = subprocess.run(
["hostname"], capture_output=True, text=True
).stdout.strip()
kernel = subprocess.run(
["uname", "-r"], capture_output=True, text=True
).stdout.strip()
affected, fixed = is_affected(kernel)
livepatch = check_livepatch() if affected else False
if not affected:
detail = "内核不受影响"
elif livepatch:
detail = f"受影响但已应用热补丁(仍建议升级到 {fixed})"
else:
detail = f"受影响,需升级到 {fixed}"
return KernelStatus(
hostname=hostname, kernel=kernel, affected=affected,
fixed_version=fixed, livepatch_applied=livepatch, detail=detail
)
def main():
parser = argparse.ArgumentParser(description="CVE-2026-46242 Bad Epoll 巡检")
parser.add_argument("--ssh-hosts", help="SSH 主机列表文件")
args = parser.parse_args()
print("=" * 70)
print("CVE-2026-46242 Bad Epoll 漏洞巡检报告")
print("=" * 70)
if args.ssh_hosts:
# 批量 SSH 巡检(示例:通过 ssh 执行 uname -r)
try:
with open(args.ssh_hosts) as f:
hosts = [line.strip() for line in f if line.strip() and not line.startswith("#")]
except FileNotFoundError:
print(f"❌ 主机列表文件 {args.ssh_hosts} 不存在")
sys.exit(1)
for host in hosts:
try:
result = subprocess.run(
["ssh", "-o", "ConnectTimeout=5", host, "uname -r"],
capture_output=True, text=True, timeout=10
)
kernel = result.stdout.strip()
if not kernel:
print(f"❌ {host}: 无法获取内核版本")
continue
affected, fixed = is_affected(kernel)
status = "🔴 受影响" if affected else "🟢 不受影响"
print(f"{status} {host} kernel={kernel} fixed={fixed or 'N/A'}")
except subprocess.TimeoutExpired:
print(f"⚠️ {host}: SSH 连接超时")
except Exception as e:
print(f"❌ {host}: {e}")
else:
# 本地巡检
status = audit_local()
print(f"主机名: {status.hostname}")
print(f"内核版本: {status.kernel}")
print(f"是否受影响: {'🔴 是' if status.affected else '🟢 否'}")
print(f"推荐修复版本: {status.fixed_version or 'N/A'}")
print(f"热补丁状态: {'✅ 已应用' if status.livepatch_applied else '❌ 未应用'}")
print(f"详情: {status.detail}")
print("=" * 70)
if __name__ == "__main__":
main()
Crontab 定时调度
cron
# /etc/cron.d/bad-epoll-audit --- CVE-2026-46242 每日巡检
# 每天 03:00 执行,结果写入日志,受影响时发邮件告警
0 3 * * * root /opt/scripts/bad_epoll_audit.py --ssh-hosts /etc/hosts.txt \
>> /var/log/bad-epoll-audit.log 2>&1; \
grep -q "受影响" /var/log/bad-epoll-audit.log && \
mail -s "[紧急] Bad Epoll 漏洞巡检发现受影响主机" ${OPS_MAIL} \
< /var/log/bad-epoll-audit.log
预防措施
- 订阅内核安全公告:订阅 linux-kernel-announce、Ubuntu security-announce、RhSA 邮件列表,PoC 公开后 24h 内启动应急响应。
- 建立内核版本资产库:用 CMDB 维护所有主机内核版本,PoC 公开后可秒级筛选受影响范围。
- 常态化热补丁能力:所有生产主机预装 livepatch/kpatch,关键漏洞可在不重启情况下快速止血。
- 定期演练:每季度演练一次内核漏洞应急响应,从发现到全量补丁完成应在 72h 内。
- 多租户隔离升级:共享内核云环境优先部署 gVisor/Kata,将内核攻击面从租户侧屏蔽。
💰 成本核算与价值量化
开发成本
| 项目 | 工作量 | 单价 | 小计 |
|---|---|---|---|
| 漏洞情报跟踪与评估 | 0.5 人天 | ¥2,000/人天 | ¥1,000 |
| 内核升级方案设计(含回退) | 1.0 人天 | ¥2,000/人天 | ¥2,000 |
| 内核热补丁验证(kpatch/livepatch) | 1.5 人天 | ¥2,500/人天 | ¥3,750 |
| 跨发行版巡检脚本开发 | 1.0 人天 | ¥2,000/人天 | ¥2,000 |
| Prometheus 监控规则 + 仪表板 | 1.0 人天 | ¥2,000/人天 | ¥2,000 |
| K8s 滚动升级演练 | 1.0 人天 | ¥2,000/人天 | ¥2,000 |
| 应急响应文档与培训 | 0.5 人天 | ¥2,000/人天 | ¥1,000 |
| 开发成本合计 | 6.5 人天 | --- | ¥13,750 |
运行成本
| 项目 | 频次 | 单次成本 | 年度成本 |
|---|---|---|---|
| 内核热补丁订阅(Ubuntu Pro) | 持续 | --- | ¥0(个人/小规模免费) |
| RHEL Livepatch 订阅 | 持续 | --- | ¥1,200/主机/年(按 50 主机计 ¥60,000) |
| 巡检脚本运行(cron) | 每日 | ¥0.5 | ¥182 |
| Prometheus 监控存储 | 持续 | --- | ¥2,000 |
| 维护窗口重启(50 主机) | 季度 | ¥200/主机 | ¥4,000 |
| 运行成本合计(首年,50 主机) | --- | --- | ¥66,182 |
收益对比
| 维度 | 不修复的潜在损失 | 修复后收益 |
|---|---|---|
| 单台服务器被提权 | 数据泄露 + 横向移动,单次事件 ¥50 万+ | 风险消除 |
| 云宿主机沦陷 | 全租户数据泄露,单次事件 ¥500 万+(含 SLA 赔付) | 宿主机隔离稳固 |
| 合规罚款 | 等保 2.0 / GDPR 罚款 ¥100 万 - ¥1,000 万 | 合规风险消除 |
| 业务中断 | 内核 panic 导致服务不可用,每小时 ¥10 万 | 业务连续性保障 |
| 品牌声誉 | 安全事件舆情损失难以量化 | 信任度维护 |
ROI 计算
text
年度成本 = 开发成本 + 运行成本 = ¥13,750 + ¥66,182 = ¥79,932
年度预期损失(50 主机规模,按 1% 概率被利用计):
= 50 主机 × 1% × ¥500,000/台 = ¥250,000
ROI = (预期损失 - 年度成本) / 年度成本
= (¥250,000 - ¥79,932) / ¥79,932
= 212%
结论:投资回报率 212%,且未计入云宿主机沦陷与合规罚款的尾部风险。
对共享内核云服务商,ROI 应按宿主机口径计算,可达 1000%+。
8. 总结与行动清单
8.1 核心收获
- Bad Epoll 是 2026 年最严重的 Linux 内核漏洞之一------99% 可靠 root 提权,影响所有 Linux 6.4+ 内核,包括 Android 6.6 系列设备。
- 漏洞根因是
ep_remove()在file->f_lock下清f_ep后继续使用file对象 ------并发的__fput()观察到瞬态 NULL,跳过同步慢路径,导致struct eventpoll被提前kfree,hlist_del_rcu()写入已释放内存。 - 竞态窗口仅约 6 条指令 ------KASAN 因
SLAB_TYPESAFE_BY_RCU失灵,Mythos AI 也错过了,最终由人工代码审查发现。 - 无运行时缓解是最大运维痛点------epoll 是用户空间事件驱动基石,无法禁用,必须打补丁 + 重启或热补丁。
- 云多租户场景风险被显著放大------共享内核的容器/serverless 环境中,任何租户获得本地 shell 即可能提权到宿主机 root,进而横扫所有租户。
- 内核热补丁是关键止血手段------kpatch/livepatch/kGraft 可在不重启情况下应用补丁,适合云宿主机与无法容忍重启的关键节点。
- HWE 内核是常见盲区------Ubuntu 22.04 默认内核不受影响,但 HWE-6.8 受影响,运维必须全量盘点。
- gVisor/Kata Containers 是云环境纵深防御------用户态内核或轻量 VM 隔离可显著缩小内核攻击面。
8.2 立即行动清单
markdown
□ **今天完成(PoC 已公开,窗口期极短)**:
- [ ] 全量盘点所有 Linux 主机内核版本(含 HWE 内核)
- [ ] 识别所有 Ubuntu 22.04 + HWE-6.8、24.04、26.04 主机
- [ ] 对云宿主机优先应用内核热补丁(livepatch/kpatch)
- [ ] 部署 epoll 异常监控(bpftrace/perf/Prometheus)
□ **本周完成**:
- [ ] 测试环境验证内核升级方案(6.18.33+ 或 7.0.10+)
- [ ] 制定 K8s 集群滚动升级计划(cordon + drain + 重启)
- [ ] 高敏感租户评估迁移到 gVisor/Kata Containers
- [ ] CI/CD runner 限制外部依赖安装(防供应链投毒链)
□ **本月完成**:
- [ ] 完成所有受影响主机的内核升级或热补丁 + 30 天内重启
- [ ] 验证 Android 设备厂商补丁状态(Pixel 9/10 等 6.6 内核)
- [ ] 建立内核漏洞应急响应流程(PoC 公开 → 24h 止血 → 72h 全量)
- [ ] 演练一次完整内核漏洞响应(从发现到全量补丁完成)
□ **持续运营**:
- [ ] 订阅内核安全公告(linux-kernel-announce / RHSA / Ubuntu)
- [ ] CMDB 维护内核版本资产库,PoC 公开后秒级筛选
- [ ] 季度演练内核漏洞应急响应
- [ ] 关键主机预装 livepatch/kpatch 工具链
参考链接
- NVD CVE-2026-46242 详情:https://nvd.nist.gov/vuln/detail/CVE-2026-46242
- Ubuntu 安全公告 CVE-2026-46242:https://ubuntu.com/security/CVE-2026-46242
- Linux 内核稳定分支补丁(commit a6dc643c6931):https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=a6dc643c6931
- 0xBlackash CVE-2026-46242 仓库(防御性研究):https://github.com/0xBlackash/CVE-2026-46242
- Corgea 研究文章 Bad Epoll turns Linux eventpoll cleanup into local root:https://corgea.com/research/cve-2026-46242-bad-epoll-linux-kernel-root
- The CyberSec Guru 深度分析 Inside CVE-2026-46242:https://thecybersecguru.com/exploits/cve-2026-46242-bad-epoll-linux-vulnerability/
- Jaeyoung Chung(首尔国立大学 CompSec Lab)公开 writeup
- kernelCTF lts-6.12.67 / COS 121-18867.294.100 公开 PoC 报告
- Canonical Livepatch 文档:https://ubuntu.com/security/livepatch
- RHEL Kernel Live Patching:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/applying-patches-with-kpatch_managing-monitoring-and-updating-the-kernel
如果这篇内容对你有帮助,欢迎点赞收藏,有问题可以在评论区交流。
真实性声明:本文基于 CVE-2026-46242 的公开 NVD 描述、Ubuntu 安全公告、Linux 内核 commit message、Corgea / CyberSec Guru / 0xBlackash 等公开研究与 PoC 仓库整理撰写。漏洞根因、修复 commit、影响版本、CVSS 等核心信息均来自上述公开情报。利用链的工程细节(KASLR 绕过、竞态拓宽、Cross-Cache 喷涂)基于公开 writeup 的原理性描述,未包含可直接执行的漏洞利用代码。受限于公开情报的完整度,部分内核版本判定与厂商 backport 状态可能随时间变化,请以各发行版官方 advisory 为准。