From: Willy Tarreau Date: Wed, 3 Oct 2018 12:22:21 +0000 (+0200) Subject: BUG/MEDIUM: h2: check that the connection is still valid at the end of init() X-Git-Tag: v1.9-dev4~88 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0f3835878dfa5c2bb280a5f8e8935270508b471a;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: h2: check that the connection is still valid at the end of init() Since commit 7505f94f9 ("MEDIUM: h2: Don't use a wake() method anymore."), the H2 mux's init() calls h2_process(). But this last one may detect an early error and call h2_release(), destroying the connection, and return -1. At this point we're screwed because the caller will still dereference the connection for various things ranging from the configuration of the proxy protocol header to the retries. We could simply return -1 here upon failure but that's not enough since the stream layer really needs to keep its connection structure allocated (to clean it up in session_kill_embryonic or for example because it holds the destination address to reconnect to when the connection goes to the backend). Thus the correct solution here is to only schedule a wakeup of the I/O callback so that the init succeeds, and that the connection is only handled later. No backport is needed, this is 1.9-specific. --- diff --git a/src/mux_h2.c b/src/mux_h2.c index b02f4c3136..62eb909b39 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -381,6 +381,7 @@ static int h2c_frt_init(struct connection *conn) h2c->wait_list.task->process = h2_io_cb; h2c->wait_list.task->context = h2c; h2c->wait_list.wait_reason = 0; + LIST_INIT(&h2c->wait_list.list); h2c->ddht = hpack_dht_alloc(h2_settings_header_table_size); if (!h2c->ddht) @@ -414,12 +415,10 @@ static int h2c_frt_init(struct connection *conn) if (t) task_queue(t); - conn_xprt_want_recv(conn); - LIST_INIT(&h2c->wait_list.list); - /* Try to read, if nothing is available yet we'll just subscribe */ - if (h2_recv(h2c)) - h2_process(h2c); + /* prepare to read something */ + conn_xprt_want_recv(conn); + tasklet_wakeup(h2c->wait_list.task); return 0; fail: if (t)