Skip to content

Fix: bound daemon HTTP connections and avoid protobuf lock copies - #658

Open
GOLDKUN wants to merge 3 commits into
chaitin:mainfrom
GOLDKUN:fix/http-server-timeouts-vet
Open

Fix: bound daemon HTTP connections and avoid protobuf lock copies#658
GOLDKUN wants to merge 3 commits into
chaitin:mainfrom
GOLDKUN:fix/http-server-timeouts-vet

Conversation

@GOLDKUN

@GOLDKUN GOLDKUN commented Sep 2, 2026

Copy link
Copy Markdown

问题

Daemon HTTP servers had no read-header, idle-connection, or header-size limits, leaving the control plane exposed to slowloris and idle HTTP/2 resource exhaustion. Separately, an e2e test copied a Protobuf request value containing the generated MessageState lock, which go vet correctly rejected.

影响

攻击者可以保持慢速或空闲连接,消耗 daemon 的连接和 goroutine 资源,导致控制面拒绝服务。按值复制 Protobuf messages 还可能复制内部同步状态并产生竞态风险。涉及 CWE-400;静态检查问题属于工程健壮性缺陷。

修复内容

  • 为 daemon HTTP servers 设置 ReadHeaderTimeoutIdleTimeoutMaxHeaderBytes
  • 为 h2c/HTTP2 设置连接 idle、read-idle、ping 和 write-byte 超时,同时不设置会破坏长连接 RPC/WebSocket 的全局 WriteTimeout
  • 使用 proto.Clone 替代按值复制 StopSandboxRequest
  • 增加连接限制回归测试。

验证

  • 新增连接限制测试已加入本 PR。
  • git diff --check

说明:测试包的完整编译当前仍被 main 基线中未同步的 Protobuf 生成文件阻塞,表现为缺少 K8SDriverSpecRunTimeout 等生成符号;本 PR 仅修复 vet 报告的按值复制问题,未改动该独立生成基线。

@monkeyscan

monkeyscan Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Title: Fix: bound daemon HTTP connections and avoid proto...

Commit: cabe41d

本次改动为守护进程的 HTTP 服务器添加连接级限制,并修正了 e2e 测试中的请求对象共享问题:

  1. cmd/agent-compose/cli_daemon.go:daemonServers.add 现在为 http.Server 设置 ReadHeaderTimeout: 5sIdleTimeout: 2minMaxHeaderBytes: 64KB,并为 h2c 的 http2.Server 设置 IdleTimeout: 2minReadIdleTimeout: 30sPingTimeout: 15sWriteByteTimeout: 30s,用于防御慢连接/空闲连接滥用。该 server 同时服务于 AGENT_COMPOSE_SOCKET(Unix socket)和 HTTP_LISTEN(TCP),而 attach 路径(AttachAgentRun bidi 流)正是通过 h2c 走此 server。

  2. cmd/agent-compose/cli_daemon_server_test.go:新增 TestDaemonServerConfiguresConnectionLimits,只断言了 http.Server 的三个字段,未覆盖 http2.Server 的超时字段。

  3. test/e2e/graceful_sandbox_stop_contract_test.go:改用 proto.Clone 深拷贝请求再修改 SandboxId,避免共享请求对象;所有测试用例的 request 均非空,无 nil 解引用风险,改动安全。

总体评估:防御性配置方向合理,e2e 测试改动是纯加固。主要风险点在于新增的 HTTP/2 超时可能中断守护进程核心的长连接 attach bidi 会话(客户端短暂不可达 >45s 或消费停滞 >30s 时连接会被主动关闭),需要确认其与交互式长会话的兼容性。

Comment thread cmd/agent-compose/cli_daemon.go
@GOLDKUN

GOLDKUN commented Sep 2, 2026

Copy link
Copy Markdown
Author

已按最新评论修订:

  • 移除 h2c ReadIdleTimeoutPingTimeoutWriteByteTimeoutIdleTimeout,避免主动中断长时间空闲或客户端暂时不可达的 attach bidi 会话。
  • 保留 HTTP server 层的 ReadHeaderTimeoutIdleTimeoutMaxHeaderBytes,继续防护慢速 Header、无界 Header 和 HTTP/1.1 空闲连接资源占用。
  • 增加断言确保长连接不会被设置全局 WriteTimeout
  • Protobuf 请求仍使用 proto.Clone,避免按值复制内部锁状态。

本地 git diff --check 通过。cmd/agent-compose 测试仍被 main 基线中未同步的 Protobuf 生成文件阻塞(缺少 K8SDriverSpecRunTimeout 等符号),与本 PR 无关。

@monkeyscan

monkeyscan Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Title: Fix: bound daemon HTTP connections and avoid proto...

Commit: 79cf45f

本次改动将 cmd/agent-compose 守护进程 HTTP 服务(daemonServers.add)中 h2c.NewHandler 的 http2.Server 从带显式超时(IdleTimeout 2m、ReadIdleTimeout 30s、PingTimeout 15s、WriteByteTimeout 30s)改为零值 &http2.Server{},并在测试中新增断言 http.Server.WriteTimeout 保持 0。

设计意图:撤销此前为连接"加固"而添加的 HTTP/2 层超时,避免其主动中断长时间运行的 Connect attach bidi 会话——这与本会话捆绑的历史 finding(66a7dab3,confirmed)所指问题一致,方向正确。清零后,静默/空闲的长连接不再被 HTTP/2 层读空闲探测与 idle GOAWAY 打断;http.Server 层仍保留 ReadHeaderTimeout 5s、IdleTimeout 2m、MaxHeaderBytes 64KB,无活动流的空闲连接仍会被回收,http.Server.WriteTimeout 为 0 也允许流长期存活。

总体评估:改动小且聚焦,基本修复了已确认的回归。两点需留意:(1) x/net 中 WriteByteTimeout 取零值时回退为默认 15s,写阻塞断连阈值由 30s 收紧到 15s(仅影响完全停读的慢消费者);(2) 移除 ReadIdleTimeout 后,有活动流但对端已静默死亡(如非本机网络断连)的连接失去 HTTP/2 层快速健康检查,只能依赖 OS TCP keepalive。主要不足是新增测试并未真正覆盖被清零的 http2.Server 配置(详见提交的 finding),无法防止已确认的长连接回归再次出现。

}
if server.WriteTimeout != 0 {
t.Fatalf("server WriteTimeout = %s, want zero for long-running streams", server.WriteTimeout)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新增测试未覆盖实际改动(http2.Server 超时清零),已确认的长连接回归仍无测试保护

本次改动的实际行为变化是把 h2c.NewHandler 的 http2.Server 配置由带显式超时(IdleTimeout 2m、ReadIdleTimeout 30s、PingTimeout 15s、WriteByteTimeout 30s)改为零值 &http2.Server{},以避免 HTTP/2 层超时主动中断长时间运行的 Connect attach bidi 会话——这正是历史已确认问题(66a7dab3)所指向的回归,本次为修复。但新增测试只断言 http.Server.WriteTimeout == 0,该字段本就不曾设置、保持 0,并不属于本次改动;真正被清零的 http2.Server 字段被封装在 h2c.NewHandler 内部,现有测试(包括 TestDaemonTCPServerAttachAgentRunBidiUsesH2C)都无法感知。若后续有人再次以"加固"名义给 http2.Server 加上 ReadIdleTimeout/WriteByteTimeout/IdleTimeout,测试仍会全部通过,该文件历史上已经发生过一次反复(先加超时、本次移除),因此回归风险是具体且已被证实的。另外需注意:x/net 对零值 http2.Server 会把 WriteByteTimeout 回退为默认 15s,即写阻塞断连阈值从 30s 收紧到 15s,与该改动"保护长流"的目标存在细微张力,值得显式决策并在测试/注释中固化。

Problem code:

Changed code at cmd/agent-compose/cli_daemon_server_test.go:36-38

Recommendation:
为本次行为补充能真正兜底的回归保护:(1) 把传入 h2c.NewHandler 的 *http2.Server 保存在 daemonServer 结构上,并在 TestDaemonServerConfiguresConnectionLimits 中断言其 ReadIdleTimeout/IdleTimeout/WriteByteTimeout 为零(或与显式意图一致);或(2) 增加集成测试——经 h2c 打开一个 Connect bidi 流并保持静默超过原 ReadIdleTimeout+PingTimeout 窗口(约 45s),断言流仍存活且连接未被服务端关闭。同时建议显式设置或注释说明 WriteByteTimeout 零值回退 15s 的语义,避免后续误以为"未设置即无写超时"。

@GOLDKUN

GOLDKUN commented Sep 2, 2026

Copy link
Copy Markdown
Author

已按最新评论再次修订:

  • 将传给 h2c.NewHandler*http2.Server 保存到 daemonServer.h2c
  • 测试现在直接断言 IdleTimeoutReadIdleTimeoutPingTimeoutWriteByteTimeout 均保持零值,防止未来重新加入会中断 attach bidi 的 HTTP/2 超时。
  • 在实现中明确注释:长连接 idle 是 Connect bidi 协议的合法状态,因此 h2c 层不设置主动断连超时;HTTP server 层的 Header/普通连接限制仍保留。

本地 git diff --check 通过;测试编译仍受 main 基线 Protobuf 生成文件不同步影响。

@monkeyscan

monkeyscan Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Title: Fix: bound daemon HTTP connections and avoid proto...

Commit: c85e248

本次变更涉及 cmd/agent-compose/cli_daemon.go 与对应测试文件,共 2 个文件。

变更内容:在 daemonServer 结构体中新增 h2c *http2.Server 字段;将 add() 中 h2c.NewHandler 原本内联使用的匿名 &http2.Server{} 提取为命名变量 h2cConfig,并同时传给 h2c.NewHandler 和存入结构体;新增注释说明必须保持 HTTP/2 连接超时禁用,因为该服务承载 Connect 长连接双向流,空闲属于协议一部分。测试文件新增断言 servers.items[0].h2c 的 IdleTimeout/ReadIdleTimeout/PingTimeout/WriteByteTimeout 全为零。

评估:这是一次行为中性的重构 + 回归防护测试。生产运行路径上 http2.Server 仍为零值配置(各超时禁用),与改动前完全一致,无行为回归;新增结构体字段仅用于让测试观测实际注入 handler 的配置实例,避免后续维护者为 h2c 配置加入超时而破坏长连接流。http.Server 上的 IdleTimeout=2 分钟仍保留,但 h2c 连接在首个请求即被 hijack 后由 http2.Server 接管,不受该字段影响,两者并不矛盾。测试断言与注释意图一致,未发现可操作的正确性、安全或可靠性问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant