news 2026/9/14 9:24:43

Envoy CVE-2026-48521 深度解析:上游 HTTP/3 经 ALPN 自动协商时的空指针崩溃

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Envoy CVE-2026-48521 深度解析:上游 HTTP/3 经 ALPN 自动协商时的空指针崩溃

Envoy CVE-2026-48521 深度解析:上游 HTTP/3 经 ALPN 自动协商时的空指针崩溃

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

Envoy 修复了 CVE-2026-48521:当集群配置为auto_config基于 ALPN 与上游自动协商协议、且上游通过 HTTP/3 应答时,进程会因空指针解引用而异常终止。这不是优雅退出,而是整个代理实例崩溃,所有在途连接被瞬间切断。受影响的是启用AutoHttpConfig且声明了http3_protocol_options的上游集群。本文基于仓库 changelog、架构文档与核心源码,还原这条从配置到崩溃的调用链,锁定最可能的空指针风险点,并给出可落地的配置与自查清单。

1:技术前置:读本文前需要搞懂的 3 个概念

ALPN 自动协商(AutoHttpConfig)

ALPN(Application-Layer Protocol Negotiation)是 TLS 握手期间双方交换"我支持哪些协议"清单的机制。Envoy 的auto_config分支语义是:具体用 HTTP/1 还是 HTTP/2,由与上游的 ALPN 协商结果决定,默认 ALPN 列表为h2,http/1.1(见 http_protocol_options.proto L102-L122)。关键点是 HTTP/3 是"条件性"协议——只有配置里声明了http3_protocol_options上游有明确通告时才启用。这个"条件性"正是崩溃土壤。

HTTP/3 通告(Alt-Svc)与通告缓存

上游是否支持 HTTP/3 由 Alt-Svc 响应头(RFC 7838)或 HTTPS DNS 资源记录通告,Envoy 把这些通告存在HttpServerPropertiesCache(alternate protocols cache)里,当前只记录同主机名同端口的条目。没有通告就只走 TCP 协议,有通告才尝试 QUIC。ConnectivityGrid的几乎所有决策(试不试 HTTP/3、记不记失败)都要先查这个缓存,缓存引用一旦为空,后续所有访问都是雷。

双池竞速与 HTTP/3 失败记忆

http3_upstream.md 描述的ConnectivityGrid同时包装一个 QUIC 池和一个 TCP 混合池:HTTP/3 已通告且健康时请求先走 QUIC 池,300ms 内没成功就并行打到 TCP 池,谁先成功谁胜出。同时,因为网络设备常拦截 UDP,Envoy 需要"记住"哪些上游的 HTTP/3 持续失败(状态机:Pending/Broken/FailedRecently/Confirmed),退避期内直接跳过 HTTP/3。探测、竞速、回退、记忆四套机制叠加,引入了大量惰性创建的对象和异步回调——任何一处时序没对齐,就可能解引用空指针。

理解了协商语义和缓存的角色,接下来看一条请求如何在代码里一步步走向崩溃。

2:崩溃链路重建:从配置加载到进程终止

以下调用链基于 conn_pool_grid.cc 的实际代码路径重建。

Step 1:配置入口。集群typed_extension_protocol_options里声明auto_config+http3_protocol_options。配置工厂强制校验:auto_config启用 HTTP/3 时必须同时给出alternate_protocols_cache_options,否则直接报"alternate protocols cache must be configured when HTTP/3 is enabled with auto_config"(config.cc L92-L98)。校验通过,ConnectivityGrid被构造,构造函数对缓存只有一句ASSERT(alternate_protocols)(conn_pool_grid.cc L349)——注意,ASSERT在 release 构建中被编译移除。

Step 2:请求进入网格。ConnectivityGrid::newStream()(L441-L501)第一行就调用getOrCreateHttp3Pool()(L450)。QUIC 池是惰性创建的:http3_pool_为空时才走createHttp3Pool()(L392-L401),http2_pool_http3_alternate_pool_同理(L381-L390、L403-L413)。

Step 3:判断是否尝试 HTTP/3。shouldAttemptHttp3()(L568-L612)用alternate_protocols_->findAlternatives(origin_)查通告缓存:有 h3 通告、未标记 broken、ALPN 能解析出 QUIC 版本,才返回 true。这里已经第一次解引用alternate_protocols_

Step 4:访问状态追踪器。shouldAttemptHttp3() && options.can_use_http3_成立后,L454-L466 连续调用getHttp3StatusTracker()(L529-L532),其内部执行alternate_protocols_->getOrCreateHttp3StatusTracker(origin_)并直接取返回值上的成员。alternate_protocols_为空,这里就是空指针解引用;debug 下 L349 的ASSERT能拦住,release 下进程直接终止。

Step 5:竞速与回调链。请求挂在WrapperCallbacks上,next_attempt_timer_(300ms,kDefaultTimeoutMs,L28)到期触发onNextAttemptTimer()(L299-L307),可能同时发起 happy-eyeballs 备选 QUIC 地址连接。任何池失败都会走ConnectionAttemptCallbacks::onPoolFailure → onConnectionAttemptFailed()(L136-L181):从connection_attempts_摘除失败尝试、判断是否只剩 TCP 池、必要时tryAnotherConnection()创建 HTTP/2 池。L146 直接执行host->hostname()打日志——失败回调携带的host参数在该路径上没有判空(同函数 L142 对另一条分支却做了host != nullptr检查)。

Step 6:标记 broken 与终止。TCP 成功而 HTTP/3 失败时,maybeMarkHttp3Broken()(L263-L268)→markHttp3Broken()(L539-L543)再次解引用alternate_protocols_。时序上,"QUIC 池创建中的异步回调"先于"缓存/追踪器就绪"执行,或网格析构(~ConnectivityGridL358-L371 置destroying_并逐个signalFailureAndDeleteSelf)与在途回调交错,都是触发解引用的窗口。

3:源码级根因锁定

官方 changelog 只声明"修复了异常进程终止",未披露具体修复 diff(当前仓库快照中该修复仅体现为 http3__fixed-crash-due-to-null-deref.rst 一条记录)。以下为基于代码结构的合理推断,非官方修复细节。

三个最可能的空指针/异常访问点:

风险点位置为什么这里会空
状态追踪器解引用conn_pool_grid.cc L454-L466 → L529-L532getHttp3StatusTracker()无条件解引用alternate_protocols_;构造函数 L349 只有ASSERT,release 构建下为空缓存直接崩溃
失败回调路径conn_pool_grid.cc L136-L181onConnectionAttemptFailedL146 解引用host->hostname()无判空;deferredDelete摘链与后续回调交错时,attempt指向的池成员可能已被析构
broken 标记路径conn_pool_grid.cc L539-L543markHttp3Broken()alternate_protocols_二次解引用,与 Step 4 同根,但发生在竞速收尾、距析构最近的时刻

另有一处值得运维注意的文档与源码不一致:架构文档描述 broken 退避为"首次 5 分钟、翻倍、上限 1 天",但 http3_status_tracker_impl.cc L8-L11 实际是初始 1 秒(DefaultExpirationTime{1})、按1 << consecutive_broken_count_指数翻倍、上限MaxConsecutiveBrokenCount = 17(即 2^17 ≈ 36 小时):

项目架构文档描述源码实际值
初始损坏期5 分钟1 秒(L9)
退避翻倍上限1 天2^17 秒 ≈ 36 小时(L11)

排障时若按文档预期观察"5 分钟内不重试 HTTP/3",会被实际行为误导。

4:修复验证:测试用例即证据

回归测试是确认修复行为的两层基线:

  1. ConnectivityGridTest.Success(conn_pool_grid_test.cc L286-L304):验证"有 h3 通告 →newStream惰性创建 QUIC 池 →onHandshakeComplete标记ConfirmedonPoolReady回传调用方"的完整正向路径;
  2. ConnectivityGridTest.DoubleFailureThenSuccessSerial(同文件 L323-L357):验证核心降级链——HTTP/3 池失败不上抛 → 备选池失败 → HTTP/2 池成功 → 最终isHttp3Broken()为真。断言里pool_failure_在回退期间被调用 0 次,正是"不崩溃、优雅降级"的直接证据;
  3. MarkBrokenWithBackoff/MarkBrokenWithBackoffMax(http3_status_tracker_impl_test.cc L67-L99、L101-L124):断言损坏期 1s → 2s → 4s → 8s 指数递增,并在 17 次后封顶 2^17 秒,锁定第 3 节表格中"源码实际值"的准确性。

本地复现(需要 Bazel 构建环境):

bazel test //test/common/http:conn_pool_grid_test bazel test //test/common/http:http3_status_tracker_impl_test

5:生产落地:auto_config + HTTP/3 上游配置与自查清单

完整可运行的最小配置(集群 + 传输层 + 过滤器):

static_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 10000 } filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager http_filters: - name: envoy.filters.http.alternate_protocols_cache typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.alternate_protocols_cache.v3.FilterConfig - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router route_config: virtual_hosts: - name: host domains: ["*"] routes: - match: { prefix: / } route: { cluster: upstream_with_h3 } clusters: - name: upstream_with_h3 connect_timeout: 5s type: STRICT_DNS load_assignment: cluster_name: upstream_with_h3 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: upstream.example.com port_value: 443 transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext sni: upstream.example.com typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions auto_config: http_protocol_options: {} http2_protocol_options: {} http3_protocol_options: {} alternate_protocols_cache_options: name: default_alternate_protocols_cache max_entries: 1024

踩坑提醒:

  • auto_confighttp_protocol_optionshttp2_protocol_optionshttp3_protocol_options三个字段缺一不可,缓存字段在启用 HTTP/3 时为强制项(config.cc L92-L98 校验);
  • http3_protocol_options只是"允许",实际启用仍取决于上游 Alt-Svc 通告,没通告就走 TCP;
  • auto_config依赖 ALPN,transport_socket必须是支持 ALPN 的 TLS 套接字,否则配置加载失败;
  • alternate_protocols_cache_options.name是缓存实例标识,同名缓存在多处引用时字段必须完全一致;
  • 启用key_value_store_config持久化时 Envoy 并发度必须为 1,否则同样报配置错误。

运维自查 Checklist(可直接复制到工单):

  • ✅ Envoy 版本已升级到包含http3__fixed-crash-due-to-null-deref.rst条目的发布(在changelogs/current/bug_fixes/或已发布版本的 changelog 目录中确认该条目)
  • ✅ 所有使用auto_config+ HTTP/3 的集群均已声明alternate_protocols_cache_options
  • ✅ HCM 过滤器链中启用envoy.filters.http.alternate_protocols_cache
  • ✅ 上游网络是否拦截 UDP 已确认;若拦截,确认依赖状态追踪器退避回退 TCP(初始仅 1 秒,排障时勿按文档"5 分钟"预期)
  • ✅ 观察upstream_http3_broken统计项增长,确认 broken 标记链路工作正常
  • ✅ 升级后以conn_pool_grid_testhttp3_status_tracker_impl_test为基线跑过回归

升级建议只有一条:升级到包含该修复的版本。确认方法很简单——拉取对应 tag 后查看changelogs/下是否存在该 bug_fixes 条目。

配置加载后,可通过 admin 接口的/config_dump核对实际生效的auto_config与缓存配置,并用/stats观察upstream_http3_broken计数。

6:仓库证据索引

  • 修复条目:changelogs/current/bug_fixes/http3__fixed-crash-due-to-null-deref.rst
  • 架构文档:source/docs/http3_upstream.md
  • 协议定义:api/envoy/extensions/upstreams/http/v3/http_protocol_options.proto
  • 核心实现:source/common/http/conn_pool_grid.cc
  • 核心实现:source/common/http/http3_status_tracker_impl.cc
  • 核心实现:source/common/http/http_server_properties_cache_impl.cc
  • 配置校验:source/extensions/upstreams/http/config.cc
  • 测试用例:test/common/http/conn_pool_grid_test.cc
  • 测试用例:test/common/http/http3_status_tracker_impl_test.cc

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 9:22:45

TCP协议详解与JavaEE应用实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 9:21:55

提示词工程实战:10个提升AI输出质量的技巧与模板

我做了三年的提示词工程&#xff0c;帮团队搭过几十套 prompt 流程&#xff0c;也踩过不少坑。只要你用 ChatGPT、Claude、文心一言这类大模型&#xff0c;不管你是做运营、写代码还是搞分析&#xff0c;提示词工程这件事迟早绕不开。很多人觉得"AI 不聪明、答非所问"…

作者头像 李华
网站建设 2026/9/14 9:20:13

AI重构光模块三温测试:从30分钟到2分钟的系统级突破

1. 光模块三温测试&#xff1a;一个被低估的“时间黑洞”你有没有见过产线工程师蹲在恒温箱前&#xff0c;盯着仪表盘上跳动的数字&#xff0c;一等就是半个多小时&#xff1f;我去年在一家光通信器件厂做产线自动化咨询时&#xff0c;亲眼看到一台价值百万的三温测试设备&…

作者头像 李华
网站建设 2026/9/14 9:19:41

基于SpringBoot的体育馆使用预约平台设计与实现(SpringBoot+Vue+MySQL)

基于SpringBoot的体育馆使用预约平台设计与实现&#xff08;SpringBootVueMySQL&#xff09; 面向综合性体育馆的场地预约平台&#xff1a;篮球场、足球场、羽毛球场等多类场地在线展示&#xff0c;用户按时段预约场地并在线支付&#xff0c;管理员统筹场地、公告与论坛内容。 …

作者头像 李华