From e6c570a22f60b246d7f694413867ff0a9c5b795b Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 11 Feb 2025 00:47:55 +0100 Subject: [PATCH] Prevent unsigned overflow in php_handle_swc() (GH-17678) The multiplication of `ZSTR_LEN(bufz)` with the `factor` can easily overflow on LLP64 architectures, causing a smaller `buf` to be allocated than expected. While there are no security implications, calling `uncompress()` with the small buffer cannot be successful (`Z_BUF_ERROR`). We avoid such superfluous calls by bailing out of the loop early in case of an overflow condition. Note that `safe_emalloc()` would not help here, since that will not prevent 32bit unsigned overflow on 64bit architectures. --- ext/standard/image.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index 177e87d21b59..eeb1f1fa2813 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -203,9 +203,14 @@ static struct gfxinfo *php_handle_swc(php_stream * stream) */ do { - szlength = ZSTR_LEN(bufz) * (factor <<= 1); + factor <<= 1; + if (ZSTR_LEN(bufz) > ULONG_MAX / factor) { + status = Z_MEM_ERROR; + break; + } + szlength = (unsigned long) (ZSTR_LEN(bufz) * factor); buf = erealloc(buf, szlength); - status = uncompress(buf, &szlength, (unsigned char *) ZSTR_VAL(bufz), ZSTR_LEN(bufz)); + status = uncompress(buf, &szlength, (unsigned char *) ZSTR_VAL(bufz), (unsigned long) ZSTR_LEN(bufz)); } while ((status==Z_BUF_ERROR)&&(factor