Commit d56f20f
net.http: fix TLS server close_idle fd-reuse race and remove dead set_read_timeout (#27542)
* net.http: fix TLS server close_idle fd-reuse race and remove dead set_read_timeout
close_idle (server_tls_idle.v): move t.mu.unlock() to after the
net.shutdown loop instead of before it. The old code dropped the lock
before calling net.shutdown, leaving a window where a worker could
race through unmark_idle → conn.shutdown() → net.close(fd), the OS
could reuse that fd for a freshly accepted socket, and the subsequent
net.shutdown would then interrupt an unrelated connection. Accepted TLS
connections are blocking sockets (accept_with_timeouts restores blocking
mode before returning), so net.shutdown returns immediately — holding
the lock across the loop does not introduce a liveness hazard.
listen_and_serve_tls (server_tls_notd_use_openssl.v): remove the
dead conn.set_read_timeout(s.read_timeout) call after accept. Accepted
connections are bound to the listener's ssl config (l.conf) via
mbedtls_ssl_setup; the per-conn conf that set_read_timeout writes to
is never bound to conn.ssl and has no effect on the live session. The
server read_timeout is already applied correctly when the SSLListener
is created with read_timeout: s.read_timeout in its config.
Fixes items 2 (dead call) and 4 (fd-reuse race) from #27433.
Co-Authored-By: WOZCODE <contact@withwoz.com>
* net.http: add Windows wakeup explanation to close_idle, use defer unlock
The Codex review of PR #27542 flagged that the lock-widening made
close_idle''s net.close(handle) and the worker''s deferred conn.shutdown()
a guaranteed double-close on Windows.
Removing net.close was the wrong fix: net.shutdown(SD_BOTH) alone does
NOT unblock a concurrent C.select() on Windows (only closesocket() does),
so workers blocked in wait_for_read would hang for up to 41 s
(mbedtls_server_read_timeout_ms) before noticing shutdown.
Keep net.close in the Windows path; the double-close is safe because:
- listen_and_serve_tls calls ch.close() before close_idle()
- the accept loop has already stopped at that point
- active handlers have called unmark_idle before w.handler.handle() runs,
so close_idle only touches truly idle handles
- the worker''s second closesocket returns WSAENOTSOCK, swallowed by or {}
Also switch to defer { t.mu.unlock() } for consistency with mark_idle
and unmark_idle.
Co-Authored-By: WOZCODE <contact@withwoz.com>
* net.http: stop close_idle/worker double-closing the TLS fd on Windows
close_idle force-closes idle handles on Windows with net.close (closesocket) to
wake a worker blocked in select(), which net.shutdown(SD_BOTH) does not do there.
But the worker's handle_conn defer then ran conn.shutdown() unconditionally,
closing the same fd a second time. Between the two closes the SOCKET value can be
reused by ANY socket the process opens -- handle reuse is process-wide on
Windows, not limited to this server's accept loop -- so the worker's second close
could land on an unrelated socket. The previous "double-close is safe" comment
only reasoned about this server's accept loop and was wrong.
Transfer ownership: close_idle records the handles it force-closed (under the
lock, Windows only), and the worker consults was_force_closed and skips its own
conn.shutdown so the fd is closed exactly once. The tracker lock stays held
across the shutdown loop: on non-Windows the worker is still the sole closer, and
the held lock keeps its unmark_idle (hence its net.close) ordered after our
net.shutdown, so the fd cannot be closed and recycled before we shut it down.
Found by Codex on #27542.
Co-Authored-By: WOZCODE <contact@withwoz.com>
* net.http: free TLS resources for force-closed idle connections
The previous fix skipped conn.shutdown() entirely for an idle TLS connection
that close_idle force-closed on Windows, to avoid closing the socket a second
time. But SSLConn.shutdown() does two jobs: it frees the mbedtls TLS resources
(SSL context, config, certs, RNG state, ALPN allocation) AND closes the socket.
Skipping it leaked all of those for every force-closed idle connection at
server shutdown.
Split the two concerns instead of bypassing cleanup: when close_idle already
owns the socket close (was_force_closed), relinquish socket ownership
(conn.owns_socket = false) and still call conn.shutdown(). shutdown() then frees
the TLS resources but skips net.close, so the fd is still closed exactly once
(by close_idle) and nothing leaks. On non-Windows was_force_closed is always
false and the worker remains the sole closer, unchanged. Found by Codex on
#27542.
Co-Authored-By: WOZCODE <contact@withwoz.com>
---------
Co-authored-by: WOZCODE <contact@withwoz.com>1 parent eef477c commit d56f20f
2 files changed
Lines changed: 59 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
15 | 21 | | |
16 | 22 | | |
17 | 23 | | |
| |||
37 | 43 | | |
38 | 44 | | |
39 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
40 | 66 | | |
41 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
42 | 71 | | |
43 | 72 | | |
44 | 73 | | |
45 | | - | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
46 | 93 | | |
47 | 94 | | |
48 | 95 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | 112 | | |
116 | 113 | | |
117 | 114 | | |
| |||
161 | 158 | | |
162 | 159 | | |
163 | 160 | | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
164 | 172 | | |
165 | 173 | | |
166 | 174 | | |
| |||
0 commit comments