From 53ec7fe46a4ed4c4559f587c499dd51e45d69bf7 Mon Sep 17 00:00:00 2001 From: Yuma Kakei Date: Mon, 26 Oct 2026 16:03:45 +0900 Subject: [PATCH 1/2] Fuzz exif thumbnail handling exif_read_data() only reads the thumbnail if $read_thumbnail is true, and exif_thumbnail() only scans the thumbnail for its dimensions if they are requested, so the exif fuzzer never reached this code. --- sapi/fuzzer/fuzzer-exif.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sapi/fuzzer/fuzzer-exif.c b/sapi/fuzzer/fuzzer-exif.c index 66de0735a727..37461d98a07e 100644 --- a/sapi/fuzzer/fuzzer-exif.c +++ b/sapi/fuzzer/fuzzer-exif.c @@ -31,7 +31,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { #ifdef HAVE_EXIF php_stream *stream; - zval stream_zv; + zval stream_zv, args[4]; if (Size > 256 * 1024) { /* Large inputs have a large impact on fuzzer performance, @@ -47,7 +47,23 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { php_stream_write(stream, (const char *) Data, Size); php_stream_to_zval(stream, &stream_zv); - fuzzer_call_php_func_zval("exif_read_data", 1, &stream_zv); + /* exif_read_data($stream, null, false, true): the thumbnail is only read if requested. */ + ZVAL_COPY_VALUE(&args[0], &stream_zv); + ZVAL_NULL(&args[1]); + ZVAL_FALSE(&args[2]); + ZVAL_TRUE(&args[3]); + fuzzer_call_php_func_zval("exif_read_data", 4, args); + + /* exif_thumbnail($stream, $width, $height, $type): the thumbnail is only scanned for its + * dimensions if they are requested. */ + for (int i = 1; i < 4; i++) { + ZVAL_NEW_EMPTY_REF(&args[i]); + ZVAL_NULL(Z_REFVAL(args[i])); + } + fuzzer_call_php_func_zval("exif_thumbnail", 4, args); + for (int i = 1; i < 4; i++) { + zval_ptr_dtor(&args[i]); + } zval_ptr_dtor(&stream_zv); From 418677b6bb785232983a1a4df95ee04aa05a50fa Mon Sep 17 00:00:00 2001 From: Yuma Kakei Date: Tue, 27 Oct 2026 21:25:22 +0900 Subject: [PATCH 2/2] Store the stream in args[0] directly --- sapi/fuzzer/fuzzer-exif.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sapi/fuzzer/fuzzer-exif.c b/sapi/fuzzer/fuzzer-exif.c index 37461d98a07e..98f571f7ccac 100644 --- a/sapi/fuzzer/fuzzer-exif.c +++ b/sapi/fuzzer/fuzzer-exif.c @@ -31,7 +31,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { #ifdef HAVE_EXIF php_stream *stream; - zval stream_zv, args[4]; + zval args[4]; if (Size > 256 * 1024) { /* Large inputs have a large impact on fuzzer performance, @@ -45,10 +45,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { stream = php_stream_memory_create(TEMP_STREAM_DEFAULT); php_stream_write(stream, (const char *) Data, Size); - php_stream_to_zval(stream, &stream_zv); + php_stream_to_zval(stream, &args[0]); /* exif_read_data($stream, null, false, true): the thumbnail is only read if requested. */ - ZVAL_COPY_VALUE(&args[0], &stream_zv); ZVAL_NULL(&args[1]); ZVAL_FALSE(&args[2]); ZVAL_TRUE(&args[3]); @@ -61,12 +60,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { ZVAL_NULL(Z_REFVAL(args[i])); } fuzzer_call_php_func_zval("exif_thumbnail", 4, args); - for (int i = 1; i < 4; i++) { + for (int i = 0; i < 4; i++) { zval_ptr_dtor(&args[i]); } - zval_ptr_dtor(&stream_zv); - /* cleanup */ php_request_shutdown(NULL);