diff --git a/sapi/fuzzer/Makefile.frag b/sapi/fuzzer/Makefile.frag index 9608e29d48910..d6cabedde7015 100644 --- a/sapi/fuzzer/Makefile.frag +++ b/sapi/fuzzer/Makefile.frag @@ -31,3 +31,6 @@ $(SAPI_FUZZER_PATH)/php-fuzz-mbstring: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP $(SAPI_FUZZER_PATH)/php-fuzz-mbregex: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_MBREGEX_OBJS) $(FUZZER_BUILD) $(PHP_FUZZER_MBREGEX_OBJS) -o $@ + +$(SAPI_FUZZER_PATH)/php-fuzz-bcmath: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_BCMATH_OBJS) + $(FUZZER_BUILD) $(PHP_FUZZER_BCMATH_OBJS) -o $@ diff --git a/sapi/fuzzer/README.md b/sapi/fuzzer/README.md index b4bb2bbe4573f..2ada5f7b79e8e 100644 --- a/sapi/fuzzer/README.md +++ b/sapi/fuzzer/README.md @@ -33,6 +33,7 @@ When running `make` it creates these binaries in `sapi/fuzzer/`: * `php-fuzz-execute`: Fuzzing the executor * `php-fuzz-function-jit`: Fuzzing the function JIT (requires --enable-opcache) * `php-fuzz-tracing-jit`: Fuzzing the tracing JIT (requires --enable-opcache) +* `php-fuzz-bcmath`: Fuzzing division (requires --enable-bcmath) Some fuzzers have a seed corpus in `sapi/fuzzer/corpus`. You can use it as follows: diff --git a/sapi/fuzzer/config.m4 b/sapi/fuzzer/config.m4 index 21a44cd6d886e..5da5ea5e71a8a 100644 --- a/sapi/fuzzer/config.m4 +++ b/sapi/fuzzer/config.m4 @@ -63,6 +63,7 @@ if test "$PHP_FUZZER" != "no"; then PHP_FUZZER_TARGET([unserialize], [PHP_FUZZER_UNSERIALIZE_OBJS]) PHP_FUZZER_TARGET([unserializehash], [PHP_FUZZER_UNSERIALIZEHASH_OBJS]) PHP_FUZZER_TARGET([json], [PHP_FUZZER_JSON_OBJS]) + PHP_FUZZER_TARGET([bcmath], [PHP_FUZZER_BCMATH_OBJS]) if test -n "$enable_exif" && test "$enable_exif" != "no"; then PHP_FUZZER_TARGET([exif], [PHP_FUZZER_EXIF_OBJS]) diff --git a/sapi/fuzzer/corpus/bcmath/1 b/sapi/fuzzer/corpus/bcmath/1 new file mode 100644 index 0000000000000..87e56bbe3c16a --- /dev/null +++ b/sapi/fuzzer/corpus/bcmath/1 @@ -0,0 +1 @@ +15,7,0 diff --git a/sapi/fuzzer/corpus/bcmath/2 b/sapi/fuzzer/corpus/bcmath/2 new file mode 100644 index 0000000000000..0fcc6ef088827 --- /dev/null +++ b/sapi/fuzzer/corpus/bcmath/2 @@ -0,0 +1 @@ +14.14,9,10 diff --git a/sapi/fuzzer/corpus/bcmath/3 b/sapi/fuzzer/corpus/bcmath/3 new file mode 100644 index 0000000000000..0b218cc599193 --- /dev/null +++ b/sapi/fuzzer/corpus/bcmath/3 @@ -0,0 +1 @@ +1.23456789,0.56,10 diff --git a/sapi/fuzzer/corpus/bcmath/4 b/sapi/fuzzer/corpus/bcmath/4 new file mode 100644 index 0000000000000..e44b29bd6715e --- /dev/null +++ b/sapi/fuzzer/corpus/bcmath/4 @@ -0,0 +1 @@ +0.00123456789,0.001,10 diff --git a/sapi/fuzzer/corpus/bcmath/5 b/sapi/fuzzer/corpus/bcmath/5 new file mode 100644 index 0000000000000..68de032118588 --- /dev/null +++ b/sapi/fuzzer/corpus/bcmath/5 @@ -0,0 +1 @@ +12345.6789,100,2 diff --git a/sapi/fuzzer/corpus/bcmath/6 b/sapi/fuzzer/corpus/bcmath/6 new file mode 100644 index 0000000000000..ba59d52f5047b --- /dev/null +++ b/sapi/fuzzer/corpus/bcmath/6 @@ -0,0 +1 @@ +12345.6,0.00001,20 diff --git a/sapi/fuzzer/fuzzer-bcmath.c b/sapi/fuzzer/fuzzer-bcmath.c new file mode 100644 index 0000000000000..4aa84e7110ea5 --- /dev/null +++ b/sapi/fuzzer/fuzzer-bcmath.c @@ -0,0 +1,165 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Saki Takamachi | + +----------------------------------------------------------------------+ + */ + + + +#include "fuzzer.h" + +#include "Zend/zend.h" +#include
+#include "main/php_main.h" + +#include +#include +#include + +#include "fuzzer-sapi.h" + +zend_long char_to_size_t(char *c) { + zend_long ret = 0; + if (*c >= '0' && *c <= '9') { + ret *= 10; + ret += *c - '0'; + } + return ret; +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + /* num1,num2,scale */ + const uint8_t *Comma1 = memchr(Data, ',', Size); + if (!Comma1) { + return 0; + } + + size_t dividend_len = Comma1 - Data; + char *dividend_str = estrndup((char *) Data, dividend_len); + Data = Comma1 + 1; + Size -= dividend_len + 1; + + const uint8_t *Comma2 = memchr(Data, ',', Size); + if (!Comma2) { + efree(dividend_str); + return 0; + } + + size_t divisor_len = Comma2 - Data; + char *divisor_str = estrndup((char *) Data, divisor_len); + Data = Comma2 + 1; + Size -= divisor_len + 1; + + char *scale_str = malloc(Size + 1); + memcpy(scale_str, Data, Size); + scale_str[Size] = '\0'; + + zend_long scale = char_to_size_t(scale_str); + free(scale_str); + + if (fuzzer_request_startup() == FAILURE) { + return 0; + } + + fuzzer_setup_dummy_frame(); + + zval result; + ZVAL_UNDEF(&result); + + zval args[4]; + ZVAL_COPY_VALUE(&args[0], &result); + ZVAL_STRINGL(&args[1], dividend_str, dividend_len); + ZVAL_STRINGL(&args[2], divisor_str, divisor_len); + ZVAL_LONG(&args[3], scale); + + fuzzer_call_php_func_zval("bcdiv", 4, args); + + zval_ptr_dtor(&result); + zval_ptr_dtor(&args[1]); + zval_ptr_dtor(&args[2]); + efree(dividend_str); + efree(divisor_str); + + fuzzer_request_shutdown(); + + return 0; +} + +#define BUF_SIZE 128 + +static inline bool rand_bool() { + return rand() & 1; +} + +static inline size_t generate_random_num_fraction(char *buf, size_t len) { + int zeros = rand() % 10; + for (int i = 0; i < zeros; i++) { + buf[len] = '0'; + len++; + } + len += snprintf(buf + len, BUF_SIZE - len, "%ld", random()); + return len; +} + +static inline size_t generate_random_num(char *buf, size_t len) { + if (rand_bool()) { + /* num < 1 */ + buf[len] = '0'; + buf[len + 1]= '.'; + len += 2; + /* fraction */ + len = generate_random_num_fraction(buf, len); + } else { + /* integer */ + len += snprintf(buf + len, BUF_SIZE - len, "%ld", random()); + if (rand_bool()) { + /* fraction */ + buf[len] = '.'; + len++; + len = generate_random_num_fraction(buf, len); + } + } + + return len; +} + +size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { + char buf[BUF_SIZE]; + size_t len = 0; + + /* num1 */ + len = generate_random_num(buf, len); + buf[len] = ','; + len++; + + /* num2 */ + len = generate_random_num(buf, len); + buf[len] = ','; + len++; + + /* scale */ + len += snprintf(buf + len, BUF_SIZE - len, "%d", rand() % 10); + + if (len > MaxSize) { + return 0; + } + memcpy(Data, buf, len); + return len; +} + +int LLVMFuzzerInitialize(int *argc, char ***argv) { + fuzzer_init_php(NULL); + + /* fuzzer_shutdown_php(); */ + return 0; +}