From 497456154e3c9d1f719b939e1a943ea225abf8d1 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 3 Dec 2017 18:56:02 +0100 Subject: [PATCH] BUG/MEDIUM: h2: enforce the per-connection stream limit h2spec reports that we unfortunately didn't enforce the per-connection stream limit that we advertise. It's important to ensure it's never crossed otherwise it's cheap for a client to create many streams. This requires the addition of a stream count. The h2c struct could be cleaned up a bit, just like the h2_detach() function where an "if" block doesn't make sense anymore since it's always true. To backport to 1.8. --- src/mux_h2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mux_h2.c b/src/mux_h2.c index bf080054e..28c5eb706 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -105,6 +105,8 @@ struct h2c { int timeout; /* idle timeout duration in ticks */ int shut_timeout; /* idle timeout duration in ticks after GOAWAY was sent */ + unsigned int nb_streams; /* number of streams in the tree */ + /* 32 bit hole here */ struct task *task; /* timeout management task */ struct eb_root streams_by_id; /* all active streams by their ID */ struct list send_list; /* list of blocked streams requesting to send */ @@ -361,6 +363,7 @@ static int h2c_frt_init(struct connection *conn) h2c->flags = H2_CF_NONE; h2c->rcvd_c = 0; h2c->rcvd_s = 0; + h2c->nb_streams = 0; h2c->dbuf = &buf_empty; h2c->dsi = -1; @@ -613,6 +616,9 @@ static struct h2s *h2c_stream_new(struct h2c *h2c, int id) LIST_INIT(&h2s->list); eb32_insert(&h2c->streams_by_id, &h2s->by_id); + h2c->nb_streams++; + if (h2c->nb_streams > h2_settings_max_concurrent_streams) + goto out_close; cs = cs_new(h2c->conn); if (!cs) @@ -630,6 +636,7 @@ static struct h2s *h2c_stream_new(struct h2c *h2c, int id) out_free_cs: cs_free(cs); out_close: + h2c->nb_streams--; eb32_delete(&h2s->by_id); pool_free(pool_head_h2s, h2s); h2s = NULL; @@ -991,6 +998,7 @@ static void h2_wake_some_streams(struct h2c *h2c, int last, uint32_t flags) if (!h2s->cs) { /* this stream was already orphaned */ + h2c->nb_streams--; eb32_delete(&h2s->by_id); pool_free(pool_head_h2s, h2s); continue; @@ -1906,6 +1914,7 @@ static int h2_process_mux(struct h2c *h2c) h2s->cs->flags &= ~CS_FL_DATA_WR_ENA; else { /* just sent the last frame for this orphaned stream */ + h2c->nb_streams--; eb32_delete(&h2s->by_id); pool_free(pool_head_h2s, h2s); } @@ -1948,6 +1957,7 @@ static int h2_process_mux(struct h2c *h2c) h2s->cs->flags &= ~CS_FL_DATA_WR_ENA; else { /* just sent the last frame for this orphaned stream */ + h2c->nb_streams--; eb32_delete(&h2s->by_id); pool_free(pool_head_h2s, h2s); } @@ -2299,6 +2309,7 @@ static void h2_detach(struct conn_stream *cs) if (h2s->by_id.node.leaf_p) { /* h2s still attached to the h2c */ + h2c->nb_streams--; eb32_delete(&h2s->by_id); /* We don't want to close right now unless we're removing the