Envoy CVE-2026-48521 修复解读:ALPN 自动协商叠加 HTTP/3 上游为何引发空指针崩溃,以及修复验证与配置要点 📅 发布时间:2026/9/14 16:16:30 👁 浏览次数: Envoy CVE-2026-48521 修复解读ALPN 自动协商叠加 HTTP/3 上游为何引发空指针崩溃以及修复验证与配置要点【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文针对 Envoy 的一次安全修复——CVE-2026-48521对应安全公告 GHSA-5vff-j9p4-38j3当集群通过 ALPN应用层协议协商TLS 握手中交换双方支持的协议列表自动选择上游协议、且上游服务器实际使用 HTTP/3 时进程可能因空指针解引用而直接崩溃。读完本文你能定位这条自动协商 HTTP/3链路上的状态对象与异步回调、掌握完整可用的 auto_config 配置写法并用仓库内既有测试验证修复后的回退行为。一、影响面速览一张表定位故障半径项目内容编号CVE-2026-48521 / GHSA-5vff-j9p4-38j3触发场景集群启用auto_config基于 ALPN 自动选择上游协议且上游经 HTTP/3 应答后果异常进程终止abnormal process termination非优雅退出根因空指针解引用null dereference修复载体收录于changelogs/current/未发布变更集的bug_fixes条目http3__fixed-crash-due-to-null-deref.rst修复版本current变更集未随已发布小版本流出以包含该条目的构建为准changelog 原文只有两行声明该编号并说明当 Envoy 配置为基于 ALPN 与上游自动选择协议、而服务器使用 HTTP/3 时修复异常进程终止。没有堆栈、没有补丁摘要——这也是为什么下文把推断与事实分开标注。为什么进程级崩溃值得单独对待边缘/中间/服务代理是长连接持有者一次段错误不只是单请求失败而是该实例上所有在途 QUIC 连接、TCP 连接与排队请求被同时丢弃对端表现为连接闪断或 5xx 风暴。相比某协议路径行为异常进程消失意味着没有任何重试语义可以兜底因此这类缺陷在代理项目中通常按高危处理。二、触发链路从配置到崩溃2.1 ALPN 自动协商的硬约束崩溃场景对应的不是固定协议explicit_http_config也不是跟随下游use_downstream_protocol_config而是HttpProtocolOptions.auto_config即 AutoHttpConfig 消息。把 proto 注释翻译成一组可核查的约束协议二选一由 ALPN 裁决该模式下集群只会用 HTTP/1 或 HTTP/2最终取 ALPN 协商结果中较高的协议无 ALPN 即降级上游不支持 ALPN 时回落到 HTTP/1传输套接字准入只允许使用支持 ALPN 的 transport socket配错会导致配置加载失败而不是运行期报错ALPN 列表传输层可自定义 ALPN但集群默认值或自定义 ALPN 失败时为h2,http/1.1HTTP/3 是条件项与 HTTP/1、HTTP/2 不同HTTP/3 不会因为出现在auto_config里就无条件启用必须同时满足配置了http3_protocol_options与存在服务器端 HTTP/3 支持的通告两个前提。第 5 条是本条目的关键自动协商链路里混入了一个取决于运行期外部输入上游通告的协议协商结果从配置决定变成了配置 × 运行期状态。2.2 为什么自动协商 HTTP/3是最脆弱的路径上游 HTTP/3 架构说明给出了这条路径额外的复杂度来源通告驱动auto_config中配置了 HTTP/3 后Envoy 只向通告过HTTP/3 支持的服务器发起 QUIC 连接通告来源是 Alt-Svc 头RFC 7838或 HTTPS DNS 资源记录没有通告则退回 HTTP/2 或 HTTP/1传输介质分裂HTTP/3 跑在 QUIC/UDP 上HTTP/1/2 跑在 TCP 上。网络设备拦截 UDP 很常见导致 QUIC 连接尝试被阻断必须回退 TCP——但反过来在 QUIC 畅通的网段又应避免无谓地发起 HTTP/2 连接需要记忆上述双向要求意味着连接代码必须记住HTTP/3 连接尝试是否持续失败据此决定是继续探测还是直接走 TCP。把这三点合起来看一条请求从进入连接池到拿到响应要经过查通告缓存 → 查 HTTP/3 健康状态 → 创建/复用惰性池 → 300ms 竞速 → 失败回调 → 标记状态这样一串跨越多个状态对象、多个回调层的动作。任何一个状态对象在特定回调时序下还没被创建就被访问就是一次空指针解引用。固定协议配置下这些对象根本不会被引入这也是为什么只有 auto_config HTTP/3 组合会触发该 CVE。三、崩溃路径上的关键成员3.1 双池竞速ConnectivityGrid 如何路由一个请求核心类 ConnectivityGrid 本身实现ConnectionPool接口内部同时持有两类池QUIC 池Http3ConnPoolImpl由createHttp3Pool()conn_pool_grid.cc 第 421-427 行经Http3::allocateConnPool创建构建TCP 混合池HttpConnPoolImplMixed由createHttp2Pool()第 415-419 行构建承担 HTTP/1 与 HTTP/2。两者都是惰性成员http3_pool_、http3_alternate_pool_、http2_pool_初始为 null首次用到时才通过getOrCreateHttp3Pool()/getOrCreateHttp2Pool()创建后者见 第 403-413 行。newStream()第 441-501 行的分派逻辑可拆成四条分支shouldAttemptHttp3()为真且请求允许can_use_http3_时首选用 HTTP/3 池若 HTTP/3 处于Pending或FailedRecently状态受 runtime flagenvoy.reloadable_features.quic_no_tcp_delay影响delay_tcp_attempt置为 false——不再等 300ms立即并行发起 TCP 尝试同时禁止 early data通告缓存中没有HTTP/3 记录时请求直接进 TCP 混合池HTTP/3 已通告且健康时请求先进 HTTP/3 池300mskDefaultTimeoutMs 300第 28 行内未成功则同时向混合池补发谁先就绪谁胜出。回调侧由WrapperCallbacks/ConnectionAttemptCallbacks承接onPoolFailure第 100-105 行会把失败上抛给父回调父回调再决定是切池还是终止。注意这些回调执行时当前池成员可能刚被创建、也可能尚未创建——惰性成员 回调密集正是空指针的典型温床该判断基于代码结构推断见第四节。3.2 通告缓存HttpServerPropertiesCache 里装的是什么HttpServerPropertiesCache 实现负责回答哪些服务器通告了 HTTP/3。两个要点通告来源目前是Alt-Svc 响应头HTTPS DNS RR 在路线图上存储范围是精确匹配的只保存与请求相同主机名、相同端口的通告不做域名级泛化。对应配置结构是 AlternateProtocolsCacheOptions字段与默认值如下字段语义默认 / 限制name缓存实例名同一名称在不同配置组件被引用时各字段必须完全一致否则加载失败必填max_entries缓存最大条目数1024近似值按 worker 线程独立执行实际可因时序略超key_value_store_config可选持久化 KV 存储把条目刷盘仅并发度为 1 时支持prepopulated_entries预填充条目以 7 天生命周期让 Envoy 对未通告的上游也尝试 HTTP/3会被 Alt-Svc 头或缓存值覆盖无canonical_suffixes可共享 Alt-Svc 条目的主机名后缀列表每项必须以.开头命中多个时取列表中第一个无3.3 失败记忆损坏期退避状态机记住哪些上游的 HTTP/3 不可用的职责由 Http3StatusTrackerImpl 承担是一个四态状态机Pending待定初始态Broken已标记损坏损坏期计时中FailedRecently损坏期刚结束、尚未被验证的过渡态Confirmed已确认可用。文档与源码的退避参数不一致以源码为准架构文档写的是首次损坏 5 分钟、再次损坏翻倍、上限 1 天而 http3_status_tracker_impl.cc 的实际实现是——初始损坏期DefaultExpirationTime{1}1 秒每次markHttp3Broken()时按1 consecutive_broken_count_指数翻倍MaxConsecutiveBrokenCount 17封顶源码注释称约一天半即 2^17 秒 ≈ 36 小时markHttp3Confirmed()把计数清零并关闭计时器。这套参数差了一个数量级排障时若按文档推算上游为何一直不走 QUIC会得出错误结论。四、空指针从哪来修复逻辑与测试闭环changelog 只声明了修复空指针解引用导致的异常进程终止未披露补丁内容因此以下来源分析基于代码结构推断不是官方修复细节惰性池成员在回调中被解引用ConnectivityGrid的三个池成员都是惰性创建。onPoolFailure→onConnectionAttemptFailed→ 切池/重试的链路上若某一步在getOrCreateXxxPool()执行前就解引用了尚为 null 的成员例如交替池http3_alternate_pool_的创建判断路径即为直接崩溃点状态追踪器未就绪Http3StatusTracker挂在通告缓存的Origin上若alternate_protocols_关联尚未建立或 origin 解析失败追踪器访问同样可能落空配置校验堵住了一个入口source/extensions/upstreams/http/config.cc 第 92-98 行 在解析期强制校验——auto_config启用 HTTP/3 而未配alternate_protocols_cache_options时直接拒绝加载报错alternate protocols cache must be configured when HTTP/3 is enabled with auto_config。这至少保证HTTP/3 已启用但通告缓存缺失的非法状态进不了运行期。工程上此类修复通常包含两部分崩溃路径上加判空/提前返回以及补一条复现该时序的回归测试。仓库内已有两条测试链路可以直接当验收标准用1. 双池回退链——ConnectivityGridTesttest/common/http/conn_pool_grid_test.ccSuccess第 286-304 行注入 Alt-Svc 通告后发起newStream断言http3Pool()已创建而http2Pool()仍为 null请求确实走了 QUIC 池握手完成后isHttp3Confirmed()为真onPoolReady透传给原始调用方DoubleFailureThenSuccessSerial第 323-357 行开启envoy.reloadable_features.http3_happy_eyeballs后验证完整降级链——HTTP/3 池失败时首次失败不向上抛pool_failure_期望调用 0 次转而尝试交替池交替池也失败后落到 HTTP/2 池并成功最终断言isHttp3Broken()为真。这条用例精确覆盖了失败回调密集、池成员多次切换的空指针高危窗口。2. 退避状态机——Http3StatusTrackerImplTesttest/common/http/http3_status_tracker_impl_test.ccMarkBrokenWithBackoff第 67-99 行依次断言损坏期1s → 2s → 4s → 8s每次到期后进入FailedRecentlyMarkBrokenWithBackoffMax第 101-124 行循环 17 次验证2^0 … 2^16秒递增之后连续两次markHttp3Broken()均停在2^17 秒封顶生效MarkBrokenThenExpiresThenConfirmedThenBrokenBroken → 到期 → Confirmed计数清零→ 再 Broken 时回到初始 1 秒。有 Bazel 环境时对应目标为bazel test //test/common/http:conn_pool_grid_test //test/common/http:http3_status_tracker_impl_test通告缓存层另有 http_server_properties_cache_impl_test.cc 可一并纳入回归基线。五、配置蓝图三处缺一不可5.1 集群侧auto_config 完整声明static_resources: 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_config下三种协议选项要写全架构文档明确要求同时指定 HTTP/1、HTTP/2、HTTP/3http3_protocol_options只是允许是否真正启用仍取决于上游通告由于 ALPN 是硬性依赖transport_socket必须换成支持 ALPN 的 TLS 套接字如上述UpstreamTlsContext默认 ALPNh2,http/1.1。5.2 过滤器侧让 Alt-Svc 头进入缓存通告不会凭空出现在缓存里需要在 HttpConnectionManager 过滤器链中启用 Alternate Protocols Cache Filter 来解析并写入 Alt-Svc 头http_filters: - name: envoy.filters.http.alternate_protocols_cache typed_config: type: type.googleapis.com/envoy.extensions.filters.http.alternate_protocols_cache.v3.FilterConfig注意该过滤器的 FilterConfig 里原有的alternate_protocols_cache_options字段已标记废弃deprecated_at_minor_version 3.0注释明确写着此字段被忽略过滤器将使用请求路由到的集群所配置的缓存。也就是说缓存声明只写在集群auto_config.alternate_protocols_cache_options一处5.1 所示过滤器侧留空即可若旧配置仍在过滤器里写选项需要清理并保证name与集群引用一致。5.3 常见坑漏配alternate_protocols_cache_options加载期直接失败报错即第四节引用的alternate protocols cache must be configured when HTTP/3 is enabled with auto_config同名缓存字段不一致同一name在不同组件被引用但字段值不等同样加载失败配了key_value_store_config但并发度 1解析期拒绝报错会带出实际并发度TLS 套接字不支持 ALPNauto_config直接配置失败不会带病运行只配了http3_protocol_options却没有上游通告、也没配prepopulated_entries配置合法但不走 QUIC——这不是 bug是设计行为。六、上线后四步检查升级到包含该修复的构建以 changelog 条目 http3__fixed-crash-due-to-null-deref.rst 进入的版本为下限优先覆盖auto_config 上游可能通告 HTTP/3的集群核对配置完整性auto_config三种协议选项齐全、alternate_protocols_cache_options已声明且各组件name一致、TLS 套接字支持 ALPN评估 UDP 可达性若上游所在网络拦截 UDPQUIC 尝试会持续失败此时系统依赖第四节状态机的指数退避回退 TCP——确认该行为isHttp3Broken置位、请求落到混合池与监控指标一致锁定回归基线以 conn_pool_grid_test.ccSuccess、DoubleFailureThenSuccessSerial与 http3_status_tracker_impl_test.cc退避序列 1s→2s→4s→8s 及 2^17 秒封顶作为升级前后对比的验收点确认失败回退与空指针防护行为未被回归。附录仓库内证据索引类别文件修复条目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、api/envoy/config/core/v3/protocol.proto过滤器定义api/envoy/extensions/filters/http/alternate_protocols_cache/v3/alternate_protocols_cache.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、test/common/http/http_server_properties_cache_impl_test.cc【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考