From eb911f46ceb05e2afce824e4175d6e699253d8f1 Mon Sep 17 00:00:00 2001 From: Yuma Kakei Date: Mon, 26 Oct 2026 15:20:33 +0900 Subject: [PATCH] Fix mbregex fuzzer not being built and truncating its input The mbregex fuzzer was only built if --enable-mbregex was passed explicitly. SAPIs are configured before extensions, so only enable_mbregex is available here, and it is unset unless the option is given, although mbregex is enabled by default together with mbstring. The fuzzer also passed its input through strlen(), dropping everything after the first NUL byte, although mb_ereg() accepts NUL bytes in both the pattern and the subject. --- sapi/fuzzer/config.m4 | 3 ++- sapi/fuzzer/fuzzer-mbregex.c | 33 ++++++++++++--------------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/sapi/fuzzer/config.m4 b/sapi/fuzzer/config.m4 index 21a44cd6d886..47ebfef76227 100644 --- a/sapi/fuzzer/config.m4 +++ b/sapi/fuzzer/config.m4 @@ -69,7 +69,8 @@ if test "$PHP_FUZZER" != "no"; then fi if test -n "$enable_mbstring" && test "$enable_mbstring" != "no"; then PHP_FUZZER_TARGET([mbstring], [PHP_FUZZER_MBSTRING_OBJS]) - if test -n "$enable_mbregex" && test "$enable_mbregex" != "no"; then + dnl mbregex is enabled by default, so enable_mbregex is usually unset here. + if test "$enable_mbregex" != "no"; then PHP_FUZZER_TARGET([mbregex], [PHP_FUZZER_MBREGEX_OBJS]) fi fi diff --git a/sapi/fuzzer/fuzzer-mbregex.c b/sapi/fuzzer/fuzzer-mbregex.c index bd119a65626f..2607fb46d6ad 100644 --- a/sapi/fuzzer/fuzzer-mbregex.c +++ b/sapi/fuzzer/fuzzer-mbregex.c @@ -33,32 +33,23 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; } - char *args[2]; - char *data = malloc(Size+1); - memcpy(data, Data, Size); - data[Size] = '\0'; - fuzzer_setup_dummy_frame(); - args[0] = data; - args[1] = "test123"; - fuzzer_call_php_func("mb_ereg", 2, args); - - args[0] = data; - args[1] = "test123"; - fuzzer_call_php_func("mb_eregi", 2, args); + /* Pass the input with its length, as strlen() would cut it off at the first NUL byte. */ + zval args[2]; + ZVAL_STRINGL(&args[0], (const char *) Data, Size); + ZVAL_STRING(&args[1], "test123"); + fuzzer_call_php_func_zval("mb_ereg", 2, args); + fuzzer_call_php_func_zval("mb_eregi", 2, args); + zval_ptr_dtor(&args[1]); - args[0] = data; - args[1] = data; - fuzzer_call_php_func("mb_ereg", 2, args); - - args[0] = data; - args[1] = data; - fuzzer_call_php_func("mb_eregi", 2, args); + ZVAL_COPY(&args[1], &args[0]); + fuzzer_call_php_func_zval("mb_ereg", 2, args); + fuzzer_call_php_func_zval("mb_eregi", 2, args); + zval_ptr_dtor(&args[0]); + zval_ptr_dtor(&args[1]); fuzzer_request_shutdown(); - - free(data); #else fprintf(stderr, "\n\nERROR:\nPHP built without mbstring, recompile with --enable-mbstring to use this fuzzer\n"); exit(1);