Envoy HTTP/3 崩溃修复深度拆解:HTTP/3 上游空指针与 CVE-2026-48521 完整指南 Envoy HTTP/3 崩溃修复深度拆解HTTP/3 上游空指针与 CVE-2026-48521 完整指南【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy集群启用 auto_config 自动协商、上游又通过 Alt-Svc 通告 HTTP/3 时Envoy 会因空指针解引用直接崩溃即 CVE-2026-48521。这项 Envoy HTTP/3 崩溃修复的触发条件、协商机制、正确配置与回归验证一次讲清。崩溃现场CVE-2026-48521 的三行 changelog修复记录 http3__fixed-crash-due-to-null-deref.rst 只写了三行但信息量足够完整CVE 编号CVE-2026-48521对应安全公告 GHSA-5vff-j9p4-38j3受影响配置模式集群HttpProtocolOptions使用auto_config分支由 ALPN应用层协议协商即 TLS 握手中双方互相报出可接受的协议列表与上游决定协议后果abnormal process termination进程级崩溃不是优雅退出。对代理而言进程就是所有在途流的容器一次崩溃意味着该实例上所有连接瞬间切断下游看到成片的连接重置上游看到成片的请求中断。对边缘网关来说这是请求级事故恢复窗口等于编排系统重新拉起实例的时间——在这之前流量要么丢弃要么绕行。协议协商的条件门auto_config ALPN 协商与 HTTP/3 的差异auto_config对应http_protocol_options.proto中的AutoHttpConfig分支HTTP/1 与 HTTP/2 是默认选手只要传输套接字支持 ALPN用哪个由协商结果决定默认列表h2,http/1.1上游不支持 ALPN 时回退 HTTP/1。HTTP/3 不同它有双重门集群必须显式声明http3_protocol_options并且上游必须通过 Alt-Svc 头RFC 7838或 HTTPS DNS 资源记录通告过自己支持 HTTP/3。没有任何通告Envoy 就不会对那个主机发起 QUIC 连接。协议启用条件回退行为HTTP/1声明即可上游不支持 ALPN 时启用HTTP/2ALPN 协商到h2协商失败时让位给 HTTP/1HTTP/3声明 上游 Alt-Svc/DNS RR 通告无通告或 UDP 受阻时回退 TCPQUIC 跑在 UDP 上而不少网络设备无差别拦截 UDP这类网络里 HTTP/3 连接尝试会持续失败。于是上游链路必须记住失败避免发起注定失败的连接——架构文档source/docs/http3_upstream.md对这条要求有完整描述它也正是本次崩溃的直接土壤。双池竞速与失败记忆ConnectivityGrid 双池里的三个角色整套机制由连接池层三个协作对象支撑空指针就藏在它们之间的接缝里。ConnectivityGrid300ms 双池竞速ConnectivityGrid本身是一个 ConnectionPool内部包装两个真实池Http3ConnPoolImplQUIC与HttpConnPoolImplMixedTCP。conn_pool_grid.cc 中newStream的分派核心if (shouldAttemptHttp3() options.can_use_http3_) { pool getOrCreateHttp3Pool(); // QUIC 池优先 } else { pool getOrCreateHttp2Pool(); // 未通告或不支持时走 TCP }HTTP/3 已通告且可用时请求先入 QUIC 池kDefaultTimeoutMs300ms内未成功同一请求再进入 TCP 混合池谁先成功谁胜出。若状态追踪器判定 HTTP/3 已 broken 或最近失败delay_tcp_attempt直接置 falseTCP 路径不再等待。http3_pool_、http2_pool_全部惰性创建——首次调用前它们都是 nullptr任何绕过 getOrCreate 直接解引用的回调路径都是空指针。HttpServerPropertiesCacheAlt-Svc 通告的账本http_server_properties_cache_impl.cc 记录哪些主机通告了 HTTP/3当前只存储与请求相同主机名和端口的通告避免跨主机误用。行为由AlternateProtocolsCacheOptions控制name缓存实例标识不同组件引用同名缓存时各字段必须一致否则配置加载失败max_entries默认 1024淘汰为近似值且每个 worker 独立执行实际条目数可略超配置prepopulated_entries以 7 天生命周期预填 HTTP/3 条目让 Envoy 对未通告的上游也尝试 HTTP/3。该缓存被网格与追踪器经由alternate_protocols_智能指针引用名称对不上或 origin 未就绪时这个引用就是空的。Http3StatusTrackerPending → Broken → FailedRecently → Confirmedhttp3_status_tracker_impl.cc 是 HTTP/3 失败后的记忆markHttp3Broken()开启退避定时器DefaultExpirationTime * (1 consecutive_broken_count_)即 1s → 2s → 4s 逐次翻倍MaxConsecutiveBrokenCount 17封顶最长退避约 2^17 秒定时器到期状态从Broken转入FailedRecentlymarkHttp3Confirmed()则把计数清零。文档与代码存在一处已知出入架构文档 http3_upstream.md 写的是首次损坏 5 分钟、再次损坏翻倍、上限 1 天而源码DefaultExpirationTime{1}是 1 秒起步、2^17 秒封顶——以源码为准。追踪器经getHttp3StatusTracker()惰性获取若状态查询先于其与网格的关联发生检查的就是空指针。⚠️ HTTP/3 上游空指针风险点与修复推断官方只披露了修复异常终止这一结果未披露 patch 细节以下是基于代码结构的推断惰性池成员。newStream先经getOrCreateHttp3Pool()建池随后WrapperCallbacks的异步回调会跨池触发tryAnotherConnection()这些回调路径中任何一处读取http3_pool_/http3_alternate_pool_时其仍为 nullptr即触发崩溃。追踪器与缓存未就绪。状态追踪器关联到alternate_protocols_的HttpServerPropertiesCache::Origin缓存未建立或 origin 解析失败时后续状态查询同样可能空引用。配置校验兜底。解析层已强制auto_config http3_protocol_options 必须伴随 alternate_protocols_cache_options否则直接拒绝加载config.cc 报错。这堵住了最典型的空状态入口但运行时时序仍靠代码自身保证。此类修复的工程形态通常是双件崩溃路径上加判空或提前返回再补一个钉死该时序的回归测试。完整配置三处缺一不可启用这条链路需要集群、过滤器、网络三处配合缺任何一处都会静默退化或加载失败。集群侧auto_config 全量声明三种协议static_resources: clusters: - name: upstream_with_h3 type: STRICT_DNS load_assignment: 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 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三种协议选项必须全部出现auto_config依赖 ALPN三个槽位缺一个都会被校验拒绝http3_protocol_options只代表允许 HTTP/3是否真正启用仍取决于上游通告alternate_protocols_cache_options.name是缓存实例标识与过滤器侧引用不一致会加载失败max_entries省略时用默认 1024传输套接字必须支持 ALPNTLS UpstreamTlsContext使用不支持 ALPN 的传输套接字会导致整个配置加载失败。过滤器侧让 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没有这个过滤器alt-svc 响应头不会被解析缓存永远为空。注意过滤器配置里的alternate_protocols_cache_options字段已标记废弃计划 3.0 移除注释明确说明该字段被忽略——过滤器直接使用请求路由所对应集群声明的缓存。规范写法是集群级声明、名称保持一致。回退行为UDP 被拦截时的降级网络拦截 UDP 时HTTP/3 连接尝试全部失败状态追踪器把该上游标记为 Broken 并进入指数退避请求直接走 TCP 池HTTP/2/1——这正是本次修复所保护的路径。在 HTTP/3 正常的网络上退避定时器到期后追踪器转回FailedRecently并重新探测避免无谓的 TCP 尝试。回归验证两条测试路径两个测试目标分别钉死回退链不崩溃与退避值正确两个性质测试文件覆盖场景Bazel 命令test/common/http/conn_pool_grid_test.ccSuccess通告存在 → QUIC 池 → ConfirmedDoubleFailureThenSuccessSerialh3 池失败 → 交替池失败 → h2 池成功且不向上抛错bazel test //test/common/http:conn_pool_grid_testtest/common/http/http3_status_tracker_impl_test.ccMarkBrokenWithBackoff1s→2s→4s→8sMarkBrokenWithBackoffMax2^17s 封顶Confirmed 重置计数bazel test //test/common/http:http3_status_tracker_impl_test即 conn_pool_grid_test.cc 与 http3_status_tracker_impl_test.cc 两个目标。升级后运行它们作为验收基线前者保证双池竞速的失败回退链完整可走后者保证退避参数与源码实现一致。运维行动清单按优先级排序第一条是唯一彻底的解升级到包含修复的版本对auto_config且上游可能通告 HTTP/3 的实例升级前空指针始终存在审视auto_config配置完整性确认三种协议选项与alternate_protocols_cache_options均在避免加载失败或缓存引用错位确认 UDP 可达性上游网络拦截 UDP 时退避机制会自动承担 HTTP/3→TCP 回退不必手工调整超时跟踪回归测试升级后运行上文两个目标确认回退链与退避行为仍被测试覆盖。对代理实例而言配置只能让回退路径更短崩溃本身要靠升级后的二进制来堵。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考