]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h2: ensure we can never send an RST_STREAM in response to an RST_STREAM
authorWilly Tarreau <w@1wt.eu>
Thu, 22 Mar 2018 16:37:05 +0000 (17:37 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 22 Mar 2018 16:37:05 +0000 (17:37 +0100)
There are some corner cases where this could happen by accident. Since
the spec explicitly forbids this (RFC7540#5.4.2), let's add a test in
the two only functions which make the RST to avoid this. Thanks to user
klzgrad for reporting this problem. Usually it is expected to be harmless
but may result in browsers issuing a warning.

This fix must be backported to 1.8.

src/mux_h2.c

index d15b0e33b797d1569df6de79a70ca37b86c07a96..7b2f5381893e6c4a823cc608963c404d51431617 100644 (file)
@@ -844,6 +844,14 @@ static int h2s_send_rst_stream(struct h2c *h2c, struct h2s *h2s)
        if (!h2s || h2s->st == H2_SS_CLOSED)
                return 1;
 
+       /* RFC7540#5.4.2: To avoid looping, an endpoint MUST NOT send a
+        * RST_STREAM in response to a RST_STREAM frame.
+        */
+       if (h2c->dft == H2_FT_RST_STREAM) {
+               ret = 1;
+               goto ignore;
+       }
+
        if (h2c_mux_busy(h2c, h2s)) {
                h2s->flags |= H2_SF_BLK_MBUSY;
                return 0;
@@ -874,6 +882,7 @@ static int h2s_send_rst_stream(struct h2c *h2c, struct h2s *h2s)
                }
        }
 
+ ignore:
        h2s->flags |= H2_SF_RST_SENT;
        h2s_close(h2s);
        return ret;
@@ -896,6 +905,14 @@ static int h2c_send_rst_stream(struct h2c *h2c, struct h2s *h2s)
        char str[13];
        int ret;
 
+       /* RFC7540#5.4.2: To avoid looping, an endpoint MUST NOT send a
+        * RST_STREAM in response to a RST_STREAM frame.
+        */
+       if (h2c->dft == H2_FT_RST_STREAM) {
+               ret = 1;
+               goto ignore;
+       }
+
        if (h2c_mux_busy(h2c, h2s)) {
                h2c->flags |= H2_CF_DEM_MBUSY;
                return 0;
@@ -928,6 +945,7 @@ static int h2c_send_rst_stream(struct h2c *h2c, struct h2s *h2s)
                }
        }
 
+ ignore:
        if (h2s->st > H2_SS_IDLE && h2s->st < H2_SS_CLOSED) {
                h2s->flags |= H2_SF_RST_SENT;
                h2s_close(h2s);