]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h1: the HTTP/1 make status code parser check for digits
authorWilly Tarreau <w@1wt.eu>
Thu, 9 Nov 2017 10:15:45 +0000 (11:15 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 9 Nov 2017 10:15:45 +0000 (11:15 +0100)
The H1 parser used by the H2 gateway was a bit lax and could validate
non-numbers in the status code. Since it computes the code on the fly
it's problematic, as "30:" is read as status code 310. Let's properly
check that it's a number now. No backport needed.

include/proto/h1.h
src/h1.c

index 4463ad06905ac2364111af00d819a63de46a68ba..ef405c49f2408ca8b45600857a54e7835ca67dae 100644 (file)
@@ -52,6 +52,7 @@ int h1_measure_trailers(const struct buffer *buf);
 #define H1_FLG_CRLF 0x10
 #define H1_FLG_TOK  0x20
 #define H1_FLG_VER  0x40
+#define H1_FLG_DIG  0x80
 
 #define HTTP_IS_CTL(x)       (h1_char_classes[(uint8_t)(x)] & H1_FLG_CTL)
 #define HTTP_IS_SEP(x)       (h1_char_classes[(uint8_t)(x)] & H1_FLG_SEP)
@@ -60,6 +61,7 @@ int h1_measure_trailers(const struct buffer *buf);
 #define HTTP_IS_CRLF(x)      (h1_char_classes[(uint8_t)(x)] & H1_FLG_CRLF)
 #define HTTP_IS_TOKEN(x)     (h1_char_classes[(uint8_t)(x)] & H1_FLG_TOK)
 #define HTTP_IS_VER_TOKEN(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_VER)
+#define HTTP_IS_DIGIT(x)     (h1_char_classes[(uint8_t)(x)] & H1_FLG_DIG)
 
 
 /* Macros used in the HTTP/1 parser, to check for the expected presence of
index f4d77e38d38832b6b9458bd25032ac6081724375..d3a20c2ed263f2285f44b5e24862a18db6633b2f 100644 (file)
--- a/src/h1.c
+++ b/src/h1.c
@@ -75,16 +75,16 @@ const unsigned char h1_char_classes[256] = {
        ['-'] = H1_FLG_TOK,
        ['.'] = H1_FLG_TOK | H1_FLG_VER,
        ['/'] = H1_FLG_SEP | H1_FLG_VER,
-       ['0'] = H1_FLG_TOK | H1_FLG_VER,
-       ['1'] = H1_FLG_TOK | H1_FLG_VER,
-       ['2'] = H1_FLG_TOK | H1_FLG_VER,
-       ['3'] = H1_FLG_TOK | H1_FLG_VER,
-       ['4'] = H1_FLG_TOK | H1_FLG_VER,
-       ['5'] = H1_FLG_TOK | H1_FLG_VER,
-       ['6'] = H1_FLG_TOK | H1_FLG_VER,
-       ['7'] = H1_FLG_TOK | H1_FLG_VER,
-       ['8'] = H1_FLG_TOK | H1_FLG_VER,
-       ['9'] = H1_FLG_TOK | H1_FLG_VER,
+       ['0'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['1'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['2'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['3'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['4'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['5'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['6'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['7'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['8'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
+       ['9'] = H1_FLG_TOK | H1_FLG_VER | H1_FLG_DIG,
        [':'] = H1_FLG_SEP,
        [';'] = H1_FLG_SEP,
        ['<'] = H1_FLG_SEP,
@@ -909,11 +909,16 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
 
        case HTTP_MSG_RPCODE:
        http_msg_rpcode:
-               if (likely(!HTTP_IS_LWS(*ptr))) {
+               if (likely(HTTP_IS_DIGIT(*ptr))) {
                        code = code * 10 + *ptr - '0';
                        EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, HTTP_MSG_RPCODE);
                }
 
+               if (unlikely(!HTTP_IS_LWS(*ptr))) {
+                       state = HTTP_MSG_RPCODE;
+                       goto http_msg_invalid;
+               }
+
                if (likely(HTTP_IS_SPHT(*ptr))) {
                        st_c_l = ptr - start - st_c;
                        EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, HTTP_MSG_RPCODE_SP);