This is an automated email from the ASF dual-hosted git repository.
sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/6.2.x by this push:
new ec65b34 TS-5019: Add total header length checks in HPACK
ec65b34 is described below
commit ec65b347b7ee68f88bac172dddf09a0ee96c1e10
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)
Conflicts:
proxy/http2/Http2Stream.h
proxy/http2/test_HPACK.cc
---
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 ++-
7 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc
index a31e0db..188cb88 100644
--- a/proxy/http2/HPACK.cc
+++ b/proxy/http2/HPACK.cc
@@ -834,7 +834,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;
@@ -842,6 +843,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;
@@ -885,6 +887,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 00a09b0..fc884af 100644
--- a/proxy/http2/HTTP2.cc
+++ b/proxy/http2/HTTP2.cc
@@ -572,12 +572,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 be863e1..ab3a4ed 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -299,6 +299,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);
}
@@ -730,6 +732,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 281a037..6e9079f 100644
--- a/proxy/http2/Http2Stream.cc
+++ b/proxy/http2/Http2Stream.cc
@@ -122,6 +122,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 5966522..0f19564 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -135,11 +135,10 @@ public:
return trailing_header;
}
- Http2ErrorCode
- decode_header_blocks(HpackHandle &hpack_handle)
+ void
+ set_request_headers(HTTPHdr &h2_headers)
{
- return http2_decode_header_blocks(&_req_header, (const uint8_t
*)header_blocks, header_blocks_length, NULL, hpack_handle,
- trailing_header);
+ _req_header.copy(&h2_headers);
}
// Check entire DATA payload length if content-length: header is exist
@@ -155,6 +154,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 4e506b3..9904981 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;
/***********************************************************************************
*
*
@@ -562,7 +563,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;
--
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].