From 36ba49eaf2e83026f184b61fd023faf73057c1c3 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 16 Jul 2026 08:05:16 -0400 Subject: [PATCH] ext/standard: reject a dechunk chunk size that overflows size_t php_dechunk() accumulated the hex chunk size with chunk_size * 16 + digit and never checked the multiply, so a size of 2^64 wrapped to 0. A zero size reads as the terminating chunk, so the filter stopped there and dropped the body it had been handed. Error out instead, as the other malformed-size cases already do. --- ext/standard/filters.c | 13 +++++-- .../tests/filters/dechunk_size_overflow.phpt | 38 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 ext/standard/tests/filters/dechunk_size_overflow.phpt diff --git a/ext/standard/filters.c b/ext/standard/filters.c index a7c0a035a239..0c08600648cd 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -1715,12 +1715,14 @@ static size_t php_dechunk(char *buf, size_t len, php_chunked_filter_data *data) data->chunk_size = 0; case CHUNK_SIZE: while (p < end) { + size_t digit; + if (*p >= '0' && *p <= '9') { - data->chunk_size = (data->chunk_size * 16) + (*p - '0'); + digit = *p - '0'; } else if (*p >= 'A' && *p <= 'F') { - data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10); + digit = *p - 'A' + 10; } else if (*p >= 'a' && *p <= 'f') { - data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10); + digit = *p - 'a' + 10; } else if (data->state == CHUNK_SIZE_START) { data->state = CHUNK_ERROR; break; @@ -1728,6 +1730,11 @@ static size_t php_dechunk(char *buf, size_t len, php_chunked_filter_data *data) data->state = CHUNK_SIZE_EXT; break; } + if (data->chunk_size > (SIZE_MAX / 16)) { + data->state = CHUNK_ERROR; + break; + } + data->chunk_size = (data->chunk_size * 16) + digit; data->state = CHUNK_SIZE; p++; } diff --git a/ext/standard/tests/filters/dechunk_size_overflow.phpt b/ext/standard/tests/filters/dechunk_size_overflow.phpt new file mode 100644 index 000000000000..ac42733e16e0 --- /dev/null +++ b/ext/standard/tests/filters/dechunk_size_overflow.phpt @@ -0,0 +1,38 @@ +--TEST-- +dechunk filter must reject a chunk size that overflows size_t +--SKIPIF-- + +--INI-- +allow_url_fopen=1 +--FILE-- + +--EXPECTF-- +string(%d) "%s +BODYDATA +0 +" +string(%d) "%s +BODYDATA +0 +" +string(5) "hello"