BUG/MEDIUM: connection: properly leave stopping list on error

The stopping-list management introduced by commit d3a88c1c3 ("MEDIUM:
connection: close front idling connection on soft-stop") missed two
error paths in the H1 and H2 muxes. The effect is that if a stream
or HPACK table couldn't be allocated for these incoming connections,
we would leave with the connection freed still attached to the
stopping_list and it would never leave it, resulting in use-after-free
hence either a crash or a data corruption.

This is marked as medium as it only happens under extreme memory pressure
or when playing with tune.fail-alloc. Other stability issues remain in
such a case so that abnormal behaviors cannot be explained by this bug
alone.

This must be backported to 2.4.
This commit is contained in:
Willy Tarreau 2022-01-12 17:24:26 +01:00
parent 9ab2fb3921
commit 3b990fe0be
2 changed files with 4 additions and 0 deletions

View File

@ -990,6 +990,8 @@ static int h1_init(struct connection *conn, struct proxy *proxy, struct session
tasklet_free(h1c->wait_event.tasklet); tasklet_free(h1c->wait_event.tasklet);
pool_free(pool_head_h1c, h1c); pool_free(pool_head_h1c, h1c);
fail_h1c: fail_h1c:
if (!conn_is_back(conn))
LIST_DEL_INIT(&conn->stopping_list);
conn->ctx = conn_ctx; // restore saved context conn->ctx = conn_ctx; // restore saved context
TRACE_DEVEL("leaving in error", H1_EV_H1C_NEW|H1_EV_H1C_END|H1_EV_H1C_ERR); TRACE_DEVEL("leaving in error", H1_EV_H1C_NEW|H1_EV_H1C_END|H1_EV_H1C_ERR);
return -1; return -1;

View File

@ -1042,6 +1042,8 @@ static int h2_init(struct connection *conn, struct proxy *prx, struct session *s
tasklet_free(h2c->wait_event.tasklet); tasklet_free(h2c->wait_event.tasklet);
pool_free(pool_head_h2c, h2c); pool_free(pool_head_h2c, h2c);
fail_no_h2c: fail_no_h2c:
if (!conn_is_back(conn))
LIST_DEL_INIT(&conn->stopping_list);
conn->ctx = conn_ctx; /* restore saved ctx */ conn->ctx = conn_ctx; /* restore saved ctx */
TRACE_DEVEL("leaving in error", H2_EV_H2C_NEW|H2_EV_H2C_END|H2_EV_H2C_ERR); TRACE_DEVEL("leaving in error", H2_EV_H2C_NEW|H2_EV_H2C_END|H2_EV_H2C_ERR);
return -1; return -1;