]> git.ipfire.org Git - thirdparty/haproxy.git/commit
IMPORT: slz/uslz: make the gzip FEXTRA field resumable
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 11 Aug 2026 16:24:33 +0000 (18:24 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Wed, 12 Aug 2026 07:14:07 +0000 (09:14 +0200)
commitc832fca6d711be8b3bf76290abf5b54cc1f141d0
treeebd810b0b72dd2ed1a1908f687f6c7151cee7951
parent7f349d2921393d34926f76a7b39c19740c287d1c
IMPORT: slz/uslz: make the gzip FEXTRA field resumable

The FEXTRA optional header field is a 2-byte little endian length followed
by that many bytes to skip, and either part can be split across calls. The
code had a fast path and a slow path for each of the two parts, and used
buf_len=0 to mean "nothing pending" but that is also true right after the
fast path has consumed the length and found the payload incomplete.

Resuming from that point took the fast path again and read the length a
second time, from what were in fact the first two payload bytes. With the
payload being "ABCDEF", XLEN became 0x4241 = 16961 instead of 6, so the
decoder skipped 16963 bytes of deflate data and the stream was lost.

This could be reproduced with a gzip stream carrying FEXTRA, FNAME,
FCOMMENT and FHCRC: it failed for input chunk size from 2 to 8 and 12
to 17, i.e. whenever a call boundary happened to fall inside the FEXTRA
field.

Let's replace the four paths by one: always stash XLEN in the header
buffer and use buf_len as the count of bytes of the whole field
consumed so far, so that below 2 we are reading the length and above
we are skipping the payload. That is resumable at any byte and needs
no special case, at the cost of skipping the payload one byte at a
time, which is fine for a field that is rare and usually a few bytes
long.

tests/uslztest.sh goes from 1438/1514 to 1488/1514.

This is libslz upstream commit f26fc5cd52abe47431832c807524262740d13450
src/uslz.c