You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2016/10/28 15:49:05 UTC

[trafficserver] 01/02: TS-5019: Add total header length checks in HPACK

This is an automated email from the ASF dual-hosted git repository.

bcall pushed a commit to branch 7.0.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 19969fe4acc2fcd52b8e9728e0df96d871b47358
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Fri Oct 28 08:18:58 2016 +0900

    TS-5019: Add total header length checks in HPACK
    
    (cherry picked from commit a5c11a863d961099af500649c4669fb711d48991)
---
 proxy/http2/HPACK.cc                | 16 +++++++++++++++-
 proxy/http2/HPACK.h                 |  6 ++++--
 proxy/http2/HTTP2.cc                |  5 ++++-
 proxy/http2/Http2ConnectionState.cc |  4 ++++
 proxy/http2/Http2Stream.cc          |  7 +++++++
 proxy/http2/Http2Stream.h           |  8 +-------
 proxy/http2/RegressionHPACK.cc      |  3 ++-
 proxy/http2/test_HPACK.cc           |  8 +++++---
 8 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc
index 9947170..68ec9f0 100644
--- a/proxy/http2/HPACK.cc
+++ b/proxy/http2/HPACK.cc
@@ -851,7 +851,8 @@ update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, Hpac
 }
 
 int64_t
-hpack_decode_header_block(HpackIndexingTable &indexing_table, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len)
+hpack_decode_header_block(HpackIndexingTable &indexing_table, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len,
+                          uint32_t max_header_size)
 {
   const uint8_t *cursor           = in_buf;
   const uint8_t *const in_buf_end = in_buf + in_buf_len;
@@ -859,6 +860,7 @@ hpack_decode_header_block(HpackIndexingTable &indexing_table, HTTPHdr *hdr, cons
   HTTPHdrImpl *hh                 = hdr->m_http;
   bool header_field_started       = false;
   bool has_http2_violation        = false;
+  uint32_t total_header_size      = 0;
 
   while (cursor < in_buf_end) {
     int64_t read_bytes = 0;
@@ -902,6 +904,18 @@ hpack_decode_header_block(HpackIndexingTable &indexing_table, HTTPHdr *hdr, cons
       cursor += read_bytes;
       continue;
     }
+
+    int name_len  = 0;
+    int value_len = 0;
+
+    field->name_get(&name_len);
+    field->value_get(&value_len);
+    total_header_size += name_len + value_len;
+
+    if (total_header_size > max_header_size) {
+      return HPACK_ERROR_SIZE_EXCEEDED_ERROR;
+    }
+
     // Store to HdrHeap
     mime_hdr_field_attach(hh->m_fields_impl, field, 1, NULL);
   }
diff --git a/proxy/http2/HPACK.h b/proxy/http2/HPACK.h
index cf57f7d..e0c60f9 100644
--- a/proxy/http2/HPACK.h
+++ b/proxy/http2/HPACK.h
@@ -30,7 +30,8 @@
 #include "HTTP.h"
 
 // It means that any header field can be compressed/decompressed by ATS
-const static int HPACK_ERROR_COMPRESSION_ERROR = -1;
+const static int HPACK_ERROR_COMPRESSION_ERROR   = -1;
+const static int HPACK_ERROR_SIZE_EXCEEDED_ERROR = -2;
 
 enum HpackFieldType {
   HPACK_FIELD_INDEX,              // [RFC 7541] 6.1. Indexed Header Field Representation
@@ -170,7 +171,8 @@ int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_e
 
 // High level interfaces
 typedef HpackIndexingTable HpackHandle;
-int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len);
+int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len,
+                                  uint32_t max_header_size);
 int64_t hpack_encode_header_block(HpackHandle &handle, uint8_t *out_buf, const size_t out_buf_len, HTTPHdr *hdr);
 
 #endif /* __HPACK_H__ */
diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc
index f26354f..ac134ef 100644
--- a/proxy/http2/HTTP2.cc
+++ b/proxy/http2/HTTP2.cc
@@ -621,12 +621,15 @@ http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const uint32_
   const char *value;
   int len;
   bool is_trailing_header = trailing_header;
-  int64_t result          = hpack_decode_header_block(handle, hdr, buf_start, buf_len);
+  int64_t result          = hpack_decode_header_block(handle, hdr, buf_start, buf_len, Http2::max_request_header_size);
 
   if (result < 0) {
     if (result == HPACK_ERROR_COMPRESSION_ERROR) {
       return HTTP2_ERROR_COMPRESSION_ERROR;
+    } else if (result == HPACK_ERROR_SIZE_EXCEEDED_ERROR) {
+      return HTTP2_ERROR_ENHANCE_YOUR_CALM;
     }
+
     return HTTP2_ERROR_PROTOCOL_ERROR;
   }
   if (len_read) {
diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc
index c14ebf3..f6a7668 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -302,6 +302,8 @@ rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
     if (result != HTTP2_ERROR_NO_ERROR) {
       if (result == HTTP2_ERROR_COMPRESSION_ERROR) {
         return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_COMPRESSION_ERROR);
+      } else if (result == HTTP2_ERROR_ENHANCE_YOUR_CALM) {
+        return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_ENHANCE_YOUR_CALM);
       } else {
         return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
       }
@@ -734,6 +736,8 @@ rcv_continuation_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
     if (result != HTTP2_ERROR_NO_ERROR) {
       if (result == HTTP2_ERROR_COMPRESSION_ERROR) {
         return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_COMPRESSION_ERROR);
+      } else if (result == HTTP2_ERROR_ENHANCE_YOUR_CALM) {
+        return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_ENHANCE_YOUR_CALM);
       } else {
         return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
       }
diff --git a/proxy/http2/Http2Stream.cc b/proxy/http2/Http2Stream.cc
index 4d3a07b..a4896b3 100644
--- a/proxy/http2/Http2Stream.cc
+++ b/proxy/http2/Http2Stream.cc
@@ -135,6 +135,13 @@ Http2Stream::main_event_handler(int event, void *edata)
   return 0;
 }
 
+Http2ErrorCode
+Http2Stream::decode_header_blocks(HpackHandle &hpack_handle)
+{
+  return http2_decode_header_blocks(&_req_header, (const uint8_t *)header_blocks, header_blocks_length, NULL, hpack_handle,
+                                    trailing_header);
+}
+
 void
 Http2Stream::send_request(Http2ConnectionState &cstate)
 {
diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h
index 924275e..121b91d 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -149,13 +149,6 @@ public:
     return trailing_header;
   }
 
-  Http2ErrorCode
-  decode_header_blocks(HpackHandle &hpack_handle)
-  {
-    return http2_decode_header_blocks(&_req_header, (const uint8_t *)header_blocks, header_blocks_length, NULL, hpack_handle,
-                                      trailing_header);
-  }
-
   void
   set_request_headers(HTTPHdr &h2_headers)
   {
@@ -176,6 +169,7 @@ public:
     return content_length == 0 || content_length == data_length;
   }
 
+  Http2ErrorCode decode_header_blocks(HpackHandle &hpack_handle);
   void send_request(Http2ConnectionState &cstate);
   VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf);
   VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuffer, bool owner = false);
diff --git a/proxy/http2/RegressionHPACK.cc b/proxy/http2/RegressionHPACK.cc
index 09ad109..94fdde3 100644
--- a/proxy/http2/RegressionHPACK.cc
+++ b/proxy/http2/RegressionHPACK.cc
@@ -29,6 +29,7 @@
 const static int DYNAMIC_TABLE_SIZE_FOR_REGRESSION_TEST = 256;
 const static int BUFSIZE_FOR_REGRESSION_TEST            = 128;
 const static int MAX_TEST_FIELD_NUM                     = 8;
+const static int MAX_REQUEST_HEADER_SIZE                = 131072;
 
 /***********************************************************************************
  *                                                                                 *
@@ -564,7 +565,7 @@ REGRESSION_TEST(HPACK_Decode)(RegressionTest *t, int, int *pstatus)
     headers->create(HTTP_TYPE_REQUEST);
 
     hpack_decode_header_block(indexing_table, headers, encoded_field_request_test_case[i].encoded_field,
-                              encoded_field_request_test_case[i].encoded_field_len);
+                              encoded_field_request_test_case[i].encoded_field_len, MAX_REQUEST_HEADER_SIZE);
 
     for (unsigned int j = 0; j < sizeof(raw_field_request_test_case[i]) / sizeof(raw_field_request_test_case[i][0]); j++) {
       const char *expected_name  = raw_field_request_test_case[i][j].raw_name;
diff --git a/proxy/http2/test_HPACK.cc b/proxy/http2/test_HPACK.cc
index 44efca3..8750d7c 100644
--- a/proxy/http2/test_HPACK.cc
+++ b/proxy/http2/test_HPACK.cc
@@ -32,6 +32,8 @@
 #include "ts/ink_args.h"
 #include "ts/TestBox.h"
 
+const static int MAX_REQUEST_HEADER_SIZE = 131072;
+
 using namespace std;
 
 AppVersionInfo appVersionInfo;
@@ -195,7 +197,7 @@ test_decoding(const string filename)
       case 'w':
         parse_line(line, 6, name, value);
         unpacked_len = unpack(value, unpacked);
-        hpack_decode_header_block(indexing_table, &decoded, unpacked, unpacked_len);
+        hpack_decode_header_block(indexing_table, &decoded, unpacked, unpacked_len, MAX_REQUEST_HEADER_SIZE);
         break;
       }
       break;
@@ -250,7 +252,7 @@ test_encoding(const string filename_in, const string filename_out)
             result = seqnum;
             break;
           }
-          hpack_decode_header_block(indexing_table_for_decoding, &decoded, encoded, written);
+          hpack_decode_header_block(indexing_table_for_decoding, &decoded, encoded, written, MAX_REQUEST_HEADER_SIZE);
           if (compare_header_fields(&decoded, &original) != 0) {
             result = seqnum;
             break;
@@ -295,7 +297,7 @@ test_encoding(const string filename_in, const string filename_out)
     result = seqnum;
     return result;
   }
-  hpack_decode_header_block(indexing_table_for_decoding, &decoded, encoded, written);
+  hpack_decode_header_block(indexing_table_for_decoding, &decoded, encoded, written, MAX_REQUEST_HEADER_SIZE);
   if (compare_header_fields(&decoded, &original) != 0) {
     result = seqnum;
     return result;

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.