This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.2.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/9.2.x by this push:
new 886190ceb Fix `COMPRESSION_ERROR` on valid HPACK input (#8817)
886190ceb is described below
commit 886190ceb74dfba49988b2a9ee5e33d670a3f5cf
Author: Menno de Gier <[email protected]>
AuthorDate: Tue May 17 01:34:59 2022 +0100
Fix `COMPRESSION_ERROR` on valid HPACK input (#8817)
* Check for leaf node after resetting byte counter
* Improve invalid decoding length
* Move error tests to test_Huffmancode
* Reject EOS symbol
(cherry picked from commit d362729d2ec4a9ae4ffdead43e5f0d680c0ea989)
---
proxy/hdrs/HuffmanCodec.cc | 45 ++++++++++++++++++++++++-------------
proxy/hdrs/test_Huffmancode.cc | 26 +++++++++++++++++++++
proxy/hdrs/unit_tests/test_XPACK.cc | 38 ++++++++++++++++++-------------
3 files changed, 78 insertions(+), 31 deletions(-)
diff --git a/proxy/hdrs/HuffmanCodec.cc b/proxy/hdrs/HuffmanCodec.cc
index 546269042..a99e30306 100644
--- a/proxy/hdrs/HuffmanCodec.cc
+++ b/proxy/hdrs/HuffmanCodec.cc
@@ -149,46 +149,61 @@ hpack_huffman_fin()
}
}
+#define MAX_HUFFMAN_CODE_LEN 30
+#define EOS 0x3fffffff
+
int64_t
huffman_decode(char *dst_start, const uint8_t *src, uint32_t src_len)
{
- char *dst_end = dst_start;
- uint8_t shift = 7;
- Node *current = HUFFMAN_TREE_ROOT;
- int byte_boundary_crossed = 0;
- bool includes_zero = false;
+ char *dst_end = dst_start;
+ uint8_t shift = 7;
+ Node *current = HUFFMAN_TREE_ROOT;
+ int nbits = 0;
+ uint32_t curr_bits = 0;
while (src_len) {
+ if (nbits > 0) {
+ curr_bits <<= 1;
+ }
if (*src & (1 << shift)) {
+ curr_bits |= 1;
current = current->right;
} else {
- current = current->left;
- includes_zero = true;
+ current = current->left;
}
+ ++nbits;
if (current->leaf_node == true) {
- *dst_end = current->ascii_code;
+ if (curr_bits == EOS) {
+ return -1;
+ }
+ nbits = 0;
+ curr_bits = 0;
+ *dst_end = current->ascii_code;
++dst_end;
- current = HUFFMAN_TREE_ROOT;
- byte_boundary_crossed = 0;
- includes_zero = false;
+ current = HUFFMAN_TREE_ROOT;
}
+
if (shift) {
--shift;
} else {
shift = 7;
++src;
--src_len;
- ++byte_boundary_crossed;
}
- if (byte_boundary_crossed > 3) {
+
+ if (nbits > MAX_HUFFMAN_CODE_LEN) {
return -1;
}
}
- if (byte_boundary_crossed > 1) {
+
+ if (nbits > 7) {
return -1;
}
- if (includes_zero) {
+
+ // Padding bits must be a prefix of EOS
+ uint8_t mask = (1 << nbits) - 1;
+ if ((mask & curr_bits) != mask) {
return -1;
}
diff --git a/proxy/hdrs/test_Huffmancode.cc b/proxy/hdrs/test_Huffmancode.cc
index 24344d7b8..6f5bf7b91 100644
--- a/proxy/hdrs/test_Huffmancode.cc
+++ b/proxy/hdrs/test_Huffmancode.cc
@@ -136,6 +136,12 @@ values_test()
int bytes = huffman_decode(dst_start, encoded_mapped.y,
encoded_size);
char ascii_value = i / 2;
+
+ // EOS is treated as invalid so check for an error
+ if (value == 0x3fffffff) {
+ assert(bytes == -1);
+ continue;
+ }
assert(dst_start[0] == ascii_value);
assert(bytes == 1);
}
@@ -171,6 +177,25 @@ encode_test()
}
}
+void
+decode_errors_test()
+{
+ const static struct {
+ char *input;
+ int input_len;
+ } test_cases[] = {
+ {(char *)"\x00", 1}, {(char *)"\xff", 1}, {(char *)"\x1f\xff", 2}, {(char
*)"\xff\xae", 2}, {(char *)"\xff\x9f\xff\xff\xff", 5},
+ };
+
+ for (unsigned int i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]);
i++) {
+ int dst_len = 2 * test_cases[i].input_len;
+ char *dst = (char *)malloc(dst_len);
+ int len = huffman_decode(dst, (uint8_t *)test_cases[i].input,
test_cases[i].input_len);
+ assert(len == -1);
+ free(dst);
+ }
+}
+
int
main()
{
@@ -180,6 +205,7 @@ main()
random_test();
}
values_test();
+ decode_errors_test();
hpack_huffman_fin();
diff --git a/proxy/hdrs/unit_tests/test_XPACK.cc
b/proxy/hdrs/unit_tests/test_XPACK.cc
index 91bd8b311..3404e6b67 100644
--- a/proxy/hdrs/unit_tests/test_XPACK.cc
+++ b/proxy/hdrs/unit_tests/test_XPACK.cc
@@ -73,22 +73,28 @@ TEST_CASE("XPACK_String", "[xpack]")
uint32_t raw_string_len;
uint8_t *encoded_field;
int encoded_field_len;
- } string_test_case[] = {{(char *)"", 0,
- (uint8_t *)"\x0"
- "",
- 1},
- {(char *)"custom-key", 10,
- (uint8_t *)"\xA"
- "custom-key",
- 11},
- {(char *)"", 0,
- (uint8_t *)"\x80"
- "",
- 1},
- {(char *)"custom-key", 10,
- (uint8_t *)"\x88"
- "\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f",
- 9}};
+ } string_test_case[] = {
+ {(char *)"", 0,
+ (uint8_t *)"\x0"
+ "",
+ 1},
+ {(char *)"custom-key", 10,
+ (uint8_t *)"\xA"
+ "custom-key",
+ 11},
+ {(char *)"", 0,
+ (uint8_t *)"\x80"
+ "",
+ 1},
+ {(char *)"custom-key", 10,
+ (uint8_t *)"\x88"
+ "\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f",
+ 9},
+ {(char *)"cw Times New Roman_σ=1", 23,
+ (uint8_t *)"\x95"
+
"\x27\x85\x37\x9a\x92\xa1\x4d\x25\xf0\xa6\xd3\xd2\x3a\xa2\xff\xff\xf6\xff\xff\x44\x01",
+ 22},
+ };
SECTION("Encoding")
{