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 <[email protected]> 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 "[email protected]" <[email protected]>.
