|
|
ef7dd4 |
From 4e372dc350be5c72b88546bf03392a5793cea179 Mon Sep 17 00:00:00 2001
|
|
|
ef7dd4 |
From: Willy Tarreau <w@1wt.eu>
|
|
|
ef7dd4 |
Date: Sun, 29 Mar 2020 08:53:31 +0200
|
|
|
ef7dd4 |
Subject: BUG/CRITICAL: hpack: never index a header into the headroom after
|
|
|
ef7dd4 |
wrapping
|
|
|
ef7dd4 |
|
|
|
ef7dd4 |
The HPACK header table is implemented as a wrapping list inside a contigous
|
|
|
ef7dd4 |
area. Headers names and values are stored from right to left while indexes
|
|
|
ef7dd4 |
are stored from left to right. When there's no more room to store a new one,
|
|
|
ef7dd4 |
we wrap to the right again, or possibly defragment it if needed. The condition
|
|
|
ef7dd4 |
do use the right part (called tailroom) or the left part (called headroom)
|
|
|
ef7dd4 |
depends on the location of the last inserted header. After wrapping happens,
|
|
|
ef7dd4 |
the code forces to stick to tailroom by pretending there's no more headroom,
|
|
|
ef7dd4 |
so that the size fit test always fails. The problem is that nothing prevents
|
|
|
ef7dd4 |
from storing a header with an empty name and empty value, resulting in a
|
|
|
ef7dd4 |
total size of zero bytes, which satisfies the condition to use the headroom.
|
|
|
ef7dd4 |
Doing this in a wrapped buffer results in changing the "front" header index
|
|
|
ef7dd4 |
and causing miscalculations on the available size and the addresses of the
|
|
|
ef7dd4 |
next headers. This may even allow to overwrite some parts of the index,
|
|
|
ef7dd4 |
opening the possibility to perform arbitrary writes into a 32-bit relative
|
|
|
ef7dd4 |
address space.
|
|
|
ef7dd4 |
|
|
|
ef7dd4 |
This patch fixes the issue by making sure the headroom is considered only
|
|
|
ef7dd4 |
when the buffer does not wrap, instead of relying on the zero size. This
|
|
|
ef7dd4 |
must be backported to all versions supporting H2, which is as far as 1.8.
|
|
|
ef7dd4 |
|
|
|
ef7dd4 |
Many thanks to Felix Wilhelm of Google Project Zero for responsibly
|
|
|
ef7dd4 |
reporting this problem with a reproducer and a detailed analysis.
|
|
|
ef7dd4 |
---
|
|
|
ef7dd4 |
src/hpack-tbl.c | 4 ++--
|
|
|
ef7dd4 |
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
ef7dd4 |
|
|
|
ef7dd4 |
diff --git a/src/hpack-tbl.c b/src/hpack-tbl.c
|
|
|
ef7dd4 |
index 70d7f35834..727ff7a17b 100644
|
|
|
ef7dd4 |
--- a/src/hpack-tbl.c
|
|
|
ef7dd4 |
+++ b/src/hpack-tbl.c
|
|
|
ef7dd4 |
@@ -346,9 +346,9 @@ int hpack_dht_insert(struct hpack_dht *dht, struct ist name, struct ist value)
|
|
|
ef7dd4 |
* room left in the tail to suit the protocol, but tests show that in
|
|
|
ef7dd4 |
* practice it almost never happens in other situations so the extra
|
|
|
ef7dd4 |
* test is useless and we simply fill the headroom as long as it's
|
|
|
ef7dd4 |
- * available.
|
|
|
ef7dd4 |
+ * available and we don't wrap.
|
|
|
ef7dd4 |
*/
|
|
|
ef7dd4 |
- if (headroom >= name.len + value.len) {
|
|
|
ef7dd4 |
+ if (prev == dht->front && headroom >= name.len + value.len) {
|
|
|
ef7dd4 |
/* install upfront and update ->front */
|
|
|
ef7dd4 |
dht->dte[head].addr = dht->dte[dht->front].addr - (name.len + value.len);
|
|
|
ef7dd4 |
dht->front = head;
|
|
|
ef7dd4 |
--
|
|
|
ef7dd4 |
2.20.1
|
|
|
ef7dd4 |
|