Skip to content

Commit fc7be36

Browse files
net.http: serialize H2MuxConn GOAWAY with the HEADERS write critical section
do_on_stream rechecks the terminal admission flags (closed/goaway/shutting_down) under smu while holding wmu, then releases smu and writes the request HEADERS still under wmu. The GOAWAY handler set c.goaway under smu only, so a GOAWAY landing between that recheck and the HEADERS write let the client open one more stream after observing GOAWAY -- a violation of RFC 7540 §6.8 ("Receivers of a GOAWAY frame MUST NOT open additional streams"). Take wmu before smu (the permitted wmu -> smu nesting) in the GOAWAY handler so c.goaway cannot be set while any writer holds wmu; the recheck in do_on_stream then becomes authoritative. The reader already acquires wmu in the SETTINGS and PING ACK paths, so this introduces no new lock-ordering or liveness property -- and it only sets a flag under wmu rather than writing, so it holds the lock more briefly than those existing paths. Found by Codex on #27413. Co-Authored-By: WOZCODE <contact@withwoz.com>
1 parent 4496950 commit fc7be36

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

vlib/net/http/h2_mux_conn.v

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,15 @@ fn (mut c H2MuxConn) dispatch_frame(frame H2Frame) ! {
10621062
}
10631063
}
10641064
H2GoawayFrame {
1065+
// Take wmu before smu (the permitted wmu -> smu nesting) so setting
1066+
// c.goaway serializes with do_on_stream's terminal-flag recheck, which
1067+
// runs under smu while holding wmu. Without this, a GOAWAY landing
1068+
// between that recheck (smu released at the end of the registration
1069+
// section) and the HEADERS write (still under wmu) lets the client
1070+
// open one more stream after observing GOAWAY (RFC 7540 6.8). Holding
1071+
// wmu here means c.goaway cannot be set while any writer is mid-section,
1072+
// so the recheck is authoritative.
1073+
c.wmu.lock()
10651074
c.smu.lock()
10661075
c.goaway = true
10671076
c.goaway_last = frame.last_stream_id
@@ -1072,6 +1081,7 @@ fn (mut c H2MuxConn) dispatch_frame(frame H2Frame) ! {
10721081
}
10731082
}
10741083
c.smu.unlock()
1084+
c.wmu.unlock()
10751085
for mut st in above {
10761086
// Streams above last_stream_id were not processed by the
10771087
// server, so they are safe to retry elsewhere (RFC 7540 6.8).

0 commit comments

Comments
 (0)