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存储的常量偏移。这一不一致导致了一个可被利用的验证盲区。
/* __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 字节——即越过了缓冲区的起始边界,导致内核内存的越界读写。
/* 修复: 使用有符号算术计算有效访问起始位置 */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; }