This is an automated email from the ASF dual-hosted git repository. bcall pushed a commit to branch 9.1.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 80aaf6669799093bbc4623d298abd96fcdb73e90 Author: Sudheer Vinukonda <sudhe...@apache.org> AuthorDate: Mon May 24 21:14:19 2021 -0700 Enforce HTTP parsing restrictions on HTTP versions supported (#7875) This change restricts allowed HTTP versions to 1.0, 1.1 on the HTTP request line to prevent potential mishandling, request smugging or other vulns due to random/arbitrary version tags Note that HTTP/2.0 and HTTP/3.0 are negotiated via ALPN on TLS and not via the HTTP request line. (cherry picked from commit f36cf6a6e5b1372916170541bec681a80b34c46f) --- proxy/hdrs/HTTP.cc | 37 +++++++++++++++++++++++++++++-------- proxy/hdrs/HTTP.h | 4 +++- proxy/http/HttpSM.cc | 4 ++++ proxy/http/HttpTransact.cc | 4 ++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/proxy/hdrs/HTTP.cc b/proxy/hdrs/HTTP.cc index 3cf0e18..793f6e8 100644 --- a/proxy/hdrs/HTTP.cc +++ b/proxy/hdrs/HTTP.cc @@ -623,12 +623,36 @@ http_hdr_type_set(HTTPHdrImpl *hh, HTTPType type) } /*------------------------------------------------------------------------- + RFC2616 specifies that HTTP version is of the format <major>.<minor> + in the request line. However, the features supported and in use are + for versions 1.0, 1.1 and 2.0 (with HTTP/3.0 being developed). HTTP/2.0 + and HTTP/3.0 are both negotiated using ALPN over TLS and not via the HTTP + request line thus leaving the versions supported on the request line to be + HTTP/1.0 and HTTP/1.1 alone. This utility checks if the HTTP Version + received in the request line is one of these and returns false otherwise -------------------------------------------------------------------------*/ -void +bool +is_version_supported(const uint8_t major, const uint8_t minor) +{ + if (major == 1) { + return minor == 1 || minor == 0; + } + + return false; +} + +bool +is_http_hdr_version_supported(const HTTPVersion &http_version) +{ + return is_version_supported(http_version.get_major(), http_version.get_minor()); +} + +bool http_hdr_version_set(HTTPHdrImpl *hh, const HTTPVersion &ver) { hh->m_version = ver; + return is_version_supported(ver.get_major(), ver.get_minor()); } /*------------------------------------------------------------------------- @@ -939,13 +963,12 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const if (err < 0) { return err; } - http_hdr_version_set(hh, version); + if (!http_hdr_version_set(hh, version)) { + return PARSE_RESULT_ERROR; + } end = real_end; parser->m_parsing_http = false; - if (version == HTTP_0_9) { - return PARSE_RESULT_ERROR; - } ParseResult ret = mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, false, max_hdr_field_size); @@ -1094,12 +1117,10 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const return PARSE_RESULT_ERROR; } - if (version == HTTP_0_9) { + if (!http_hdr_version_set(hh, version)) { return PARSE_RESULT_ERROR; } - http_hdr_version_set(hh, version); - end = real_end; parser->m_parsing_http = false; } diff --git a/proxy/hdrs/HTTP.h b/proxy/hdrs/HTTP.h index 3214c98..dabde58 100644 --- a/proxy/hdrs/HTTP.h +++ b/proxy/hdrs/HTTP.h @@ -422,7 +422,7 @@ inkcoreapi int http_hdr_print(HdrHeap *heap, HTTPHdrImpl *hh, char *buf, int buf void http_hdr_describe(HdrHeapObjImpl *obj, bool recurse = true); -inkcoreapi void http_hdr_version_set(HTTPHdrImpl *hh, const HTTPVersion &ver); +inkcoreapi bool http_hdr_version_set(HTTPHdrImpl *hh, const HTTPVersion &ver); const char *http_hdr_method_get(HTTPHdrImpl *hh, int *length); inkcoreapi void http_hdr_method_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *method, int16_t method_wks_idx, int method_length, @@ -460,6 +460,8 @@ HTTPValRange* http_parse_range (const char *buf, Arena *arena); */ HTTPValTE *http_parse_te(const char *buf, int len, Arena *arena); +inkcoreapi bool is_http_hdr_version_supported(const HTTPVersion &http_version); + class IOBufferReader; class HTTPHdr : public MIMEHdr diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 856c110..68a6343 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -823,6 +823,10 @@ HttpSM::state_read_client_request_header(int event, void *data) t_state.http_return_code = HTTP_STATUS_REQUEST_URI_TOO_LONG : t_state.http_return_code = HTTP_STATUS_NONE; + if (!is_http_hdr_version_supported(t_state.hdr_info.client_request.version_get())) { + t_state.http_return_code = HTTP_STATUS_HTTPVER_NOT_SUPPORTED; + } + call_transact_and_set_next_state(HttpTransact::BadRequest); break; diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc index d6aa874..8f76c14 100644 --- a/proxy/http/HttpTransact.cc +++ b/proxy/http/HttpTransact.cc @@ -818,6 +818,10 @@ HttpTransact::BadRequest(State *s) status = s->http_return_code; reason = "Field not implemented"; body_factory_template = "transcoding#unsupported"; + break; + case HTTP_STATUS_HTTPVER_NOT_SUPPORTED: + status = s->http_return_code; + reason = "Unsupported HTTP Version"; default: break; }