From 094ecf19f938e9b6c9fb6fcc4fc907776c437d27 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 26 Jan 2023 11:12:11 +0100 Subject: [PATCH] BUG/MEDIUM: hpack: fix incorrect huffman decoding of some control chars Commit 9f4f6b038 ("OPTIM: hpack-huff: reduce the cache footprint of the huffman decoder") replaced the large tables with more space efficient byte arrays, but one table, rht_bit15_11_11_4, has a 64 bytes hole in it that wasn't materialized by filling it with zeroes to make the offsets match, nor by adjusting the offset from the caller. This resulted in some control chars not properly being decoded and being seen as byte 0, and the associated messages to be rejected, as can be seen in issue #1971. This commit fixes it by adjusting the offset used for the higher part of the table so that we don't need to store 64 zeroes that will never be accessed. This needs to be backported to 2.7. Thanks to Christopher for spotting the bug, and to Juanga Covas for providing precious traces showing the problem. --- src/hpack-huff.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hpack-huff.c b/src/hpack-huff.c index 2d9513410..77743be08 100644 --- a/src/hpack-huff.c +++ b/src/hpack-huff.c @@ -608,8 +608,10 @@ uint8_t rht_bit15_8[256] = { /* below two non-overlapping tables are merged in order to save on L1D: * - bits 15-11 for values 0x00-0x1f * - bits 11-4 for values 0x60-0xff + * Note that there's no data between 0x20 and 0x5f, the caller must + * adjust its offsets by subtracting 0x40 for values 0x60 and above. */ -uint8_t rht_bit15_11_11_4[256] = { +uint8_t rht_bit15_11_11_4[192] = { /* part used for bits 15-11 (0x00-0x1f) */ /* 0x00 */ 0x5c, 0x5c, 0x5c, 0x5c, /* 0x04 */ 0xc3, 0xc3, 0xc3, 0xc3, @@ -627,7 +629,7 @@ uint8_t rht_bit15_11_11_4[256] = { /* 0x1e */ 0xa7, /* 0x1f */ 0xac, - /* part used for bits 11-4 for 0xf600 (0x60-0xff) */ + /* part used for bits 11-4 for 0xf600 (0x60-0xff), starting @0x20 */ /* 0x60 */ 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, /* 0x68 */ 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, /* 0x70 */ 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, @@ -816,12 +818,12 @@ int huff_dec(const uint8_t *huff, int hlen, char *out, int olen) } else { /* 0xff 0xff 0xf6..0xff */ - sym = code >> 4; + sym = code >> 4; /* sym = 0x60..0xff */ l = sym < 0xbc ? sym < 0x80 ? 25 : 26 : sym < 0xe2 ? 27 : sym < 0xff ? 28 : 30; if (sym < 0xff) - sym = rht_bit15_11_11_4[(code >> 4) & 0xff]; + sym = rht_bit15_11_11_4[((code >> 4) & 0xff) - 0x40L]; else if ((code & 0xff) == 0xf0) sym = 10; else if ((code & 0xff) == 0xf4)