]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: report a dead rhttp connection in h2_wake()
authorWilly Tarreau <w@1wt.eu>
Tue, 6 Oct 2026 20:42:47 +0000 (22:42 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 12 Oct 2026 12:31:04 +0000 (14:31 +0200)
When an outgoing rhttp connection to an rhttp gateway fails, h2_wake()
releases the connection but returns continues to return ret >= 0, making
its caller (sock_conn_iocb() here or the SSL handshake code) continue to
dereference the connection to read conn->flags for example. This is
visible when running with -dMuaf that instantly causes a use-after-free
on a small config like this one:

  frontend fe
      bind "rhttp@be-outgoing/gateway"

  backend be-outgoing
      server gateway 127.0.0.1:1 proto h2

Starting this config is sufficient to make the frontend trigger pre-
connectionns on the backend and cause a crash:

  (gdb) bt
  #0  sock_conn_iocb (fd=<optimized out>) at src/sock.c:1168
  #1  0x0000000000836265 in fd_update_events (fd=<optimized out>, evts=<optimized out>) at src/fd.c:793
  #2  0x000000000051c564 in _do_poll (p=<optimized out>, exp=<optimized out>, wake=<optimized out>) at src/ev_epoll.c:345
  #3  0x0000000000784c3f in run_poll_loop () at src/haproxy.c:3148
  #4  0x000000000078537f in run_thread_poll_loop (data=<optimized out>) at src/haproxy.c:3296
  #5  0x00000000004b5a75 in main (argc=<optimized out>, argv=0x7ffe5682d7a8) at src/haproxy.c:4112

This was introduced in 2.9 by commit 5053e8914 ("MEDIUM: h2: prevent
stream opening before connection reverse completed") so the fix must
be backported to 3.0. Note that this is an experimental feature.

src/mux_h2.c

index 7455b3238f44b5c6989740030d4c6b1b59ec23d2..a393f8632b17240460fe466f32b3e47f247b8b87 100644 (file)
@@ -5425,6 +5425,7 @@ static int h2_wake(struct connection *conn)
                if (unlikely(conn_reverse_in_preconnect(conn)) && h2c_is_dead(h2c)) {
                        TRACE_DEVEL("leaving and killing dead connection", H2_EV_STRM_END, h2c->conn);
                        h2_release(h2c);
+                       ret = -1;
                }
        }