By default, HTTP/1 status codes are not limited in the parser. However,
the value is stored in a 16-bit field, meaning that it may be truncated
if too large. Let's just restrict to 3-digits by default, and permit to
relax the check when accept-unsafe-violations is set, provided that the
value still fits in 16 bits.
This could be backported to latest LTS release.
When this option is set, the following rules are observed:
+ * In H1 only, status codes longer than 3 digits but whose value fits in 16
+ bits are not rejected.
+
* In H1 only, invalid characters, including NULL character, in header name
will not be rejected; however the header will be dropped.
case H1_MSG_RPCODE:
http_msg_rpcode:
if (likely(HTTP_IS_DIGIT(*ptr))) {
+ if (ptr - sl.st.c.ptr >= 3) {
+ /* more than 3 digits */
+ if (h1m->err_pos == -1) /* only capture the error pointer */
+ h1m->err_pos = ptr - start + skip;
+ else if (h1m->err_pos < -1 || sl.st.status >= ((uint16_t)~0 - 9) / 10) {
+ /* strict checks or risk of overflow */
+ state = H1_MSG_RPCODE;
+ goto http_msg_invalid;
+ }
+ }
sl.st.status = sl.st.status * 10 + *ptr - '0';
EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, H1_MSG_RPCODE);
}