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;
   }

Reply via email to