mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Add fuzzer for function JIT
This is a basic fuzzer for the function JIT, which looks for crashes and sanitizer violations only, and does not try to detect differing behavior yet.
This commit is contained in:
parent
d2eccd4405
commit
cd4243dde9
15 changed files with 228 additions and 94 deletions
|
@ -2811,6 +2811,7 @@ static inline int accel_find_sapi(void)
|
||||||
"apache2handler",
|
"apache2handler",
|
||||||
"litespeed",
|
"litespeed",
|
||||||
"uwsgi",
|
"uwsgi",
|
||||||
|
"fuzzer",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
const char **sapi_name;
|
const char **sapi_name;
|
||||||
|
|
|
@ -8,6 +8,9 @@ $(SAPI_FUZZER_PATH)/php-fuzz-parser: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_F
|
||||||
$(SAPI_FUZZER_PATH)/php-fuzz-execute: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_EXECUTE_OBJS)
|
$(SAPI_FUZZER_PATH)/php-fuzz-execute: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_EXECUTE_OBJS)
|
||||||
$(FUZZER_BUILD) $(PHP_FUZZER_EXECUTE_OBJS) -o $@
|
$(FUZZER_BUILD) $(PHP_FUZZER_EXECUTE_OBJS) -o $@
|
||||||
|
|
||||||
|
$(SAPI_FUZZER_PATH)/php-fuzz-jit: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_JIT_OBJS)
|
||||||
|
$(FUZZER_BUILD) $(PHP_FUZZER_JIT_OBJS) -o $@
|
||||||
|
|
||||||
$(SAPI_FUZZER_PATH)/php-fuzz-unserialize: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_UNSERIALIZE_OBJS)
|
$(SAPI_FUZZER_PATH)/php-fuzz-unserialize: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_UNSERIALIZE_OBJS)
|
||||||
$(FUZZER_BUILD) $(PHP_FUZZER_UNSERIALIZE_OBJS) -o $@
|
$(FUZZER_BUILD) $(PHP_FUZZER_UNSERIALIZE_OBJS) -o $@
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ When running `make` it creates these binaries in `sapi/fuzzer/`:
|
||||||
* `php-fuzz-exif`: Fuzzing `exif_read_data()` function (requires --enable-exif)
|
* `php-fuzz-exif`: Fuzzing `exif_read_data()` function (requires --enable-exif)
|
||||||
* `php-fuzz-mbstring`: Fuzzing `mb_ereg[i]()` (requires --enable-mbstring)
|
* `php-fuzz-mbstring`: Fuzzing `mb_ereg[i]()` (requires --enable-mbstring)
|
||||||
* `php-fuzz-execute`: Fuzzing the executor
|
* `php-fuzz-execute`: Fuzzing the executor
|
||||||
|
* `php-fuzz-jit`: Fuzzing the function JIT (requires --enable-opcache)
|
||||||
|
|
||||||
Some fuzzers have a seed corpus in `sapi/fuzzer/corpus`. You can use it as follows:
|
Some fuzzers have a seed corpus in `sapi/fuzzer/corpus`. You can use it as follows:
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ if test "$PHP_FUZZER" != "no"; then
|
||||||
|
|
||||||
PHP_FUZZER_TARGET([parser], PHP_FUZZER_PARSER_OBJS)
|
PHP_FUZZER_TARGET([parser], PHP_FUZZER_PARSER_OBJS)
|
||||||
PHP_FUZZER_TARGET([execute], PHP_FUZZER_EXECUTE_OBJS)
|
PHP_FUZZER_TARGET([execute], PHP_FUZZER_EXECUTE_OBJS)
|
||||||
|
PHP_FUZZER_TARGET([jit], PHP_FUZZER_JIT_OBJS)
|
||||||
PHP_FUZZER_TARGET([unserialize], PHP_FUZZER_UNSERIALIZE_OBJS)
|
PHP_FUZZER_TARGET([unserialize], PHP_FUZZER_UNSERIALIZE_OBJS)
|
||||||
PHP_FUZZER_TARGET([unserializehash], PHP_FUZZER_UNSERIALIZEHASH_OBJS)
|
PHP_FUZZER_TARGET([unserializehash], PHP_FUZZER_UNSERIALIZEHASH_OBJS)
|
||||||
PHP_FUZZER_TARGET([json], PHP_FUZZER_JSON_OBJS)
|
PHP_FUZZER_TARGET([json], PHP_FUZZER_JSON_OBJS)
|
||||||
|
|
99
sapi/fuzzer/fuzzer-execute-common.h
Normal file
99
sapi/fuzzer/fuzzer-execute-common.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| 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: Nikita Popov <nikic@php.net> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <main/php.h>
|
||||||
|
|
||||||
|
#include "fuzzer.h"
|
||||||
|
#include "fuzzer-sapi.h"
|
||||||
|
|
||||||
|
#define MAX_STEPS 1000
|
||||||
|
#define MAX_SIZE (8 * 1024)
|
||||||
|
static uint32_t steps_left;
|
||||||
|
static bool bailed_out = false;
|
||||||
|
|
||||||
|
/* Because the fuzzer is always compiled with clang,
|
||||||
|
* we can assume that we don't use global registers / hybrid VM. */
|
||||||
|
typedef int (ZEND_FASTCALL *opcode_handler_t)(zend_execute_data *);
|
||||||
|
|
||||||
|
static zend_always_inline void fuzzer_step(void) {
|
||||||
|
if (--steps_left == 0) {
|
||||||
|
/* Reset steps before bailing out, so code running after bailout (e.g. in
|
||||||
|
* destructors) will get another MAX_STEPS, rather than UINT32_MAX steps. */
|
||||||
|
steps_left = MAX_STEPS;
|
||||||
|
bailed_out = true;
|
||||||
|
zend_bailout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fuzzer_execute_ex(zend_execute_data *execute_data) {
|
||||||
|
while (1) {
|
||||||
|
int ret;
|
||||||
|
fuzzer_step();
|
||||||
|
if ((ret = ((opcode_handler_t) EX(opline)->handler)(execute_data)) != 0) {
|
||||||
|
if (ret > 0) {
|
||||||
|
execute_data = EG(current_execute_data);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_op_array *(*orig_compile_string)(zend_string *source_string, const char *filename);
|
||||||
|
|
||||||
|
static zend_op_array *fuzzer_compile_string(zend_string *str, const char *filename) {
|
||||||
|
if (ZSTR_LEN(str) > MAX_SIZE) {
|
||||||
|
/* Avoid compiling huge inputs via eval(). */
|
||||||
|
zend_bailout();
|
||||||
|
}
|
||||||
|
|
||||||
|
return orig_compile_string(str, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void (*orig_execute_internal)(zend_execute_data *execute_data, zval *return_value);
|
||||||
|
|
||||||
|
static void fuzzer_execute_internal(zend_execute_data *execute_data, zval *return_value) {
|
||||||
|
fuzzer_step();
|
||||||
|
|
||||||
|
uint32_t num_args = ZEND_CALL_NUM_ARGS(execute_data);
|
||||||
|
for (uint32_t i = 0; i < num_args; i++) {
|
||||||
|
/* Some internal functions like preg_replace() may be slow on large inputs.
|
||||||
|
* Limit the maximum size of string inputs. */
|
||||||
|
zval *arg = ZEND_CALL_VAR_NUM(execute_data, i);
|
||||||
|
if (Z_TYPE_P(arg) == IS_STRING && Z_STRLEN_P(arg) > MAX_SIZE) {
|
||||||
|
zend_bailout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig_execute_internal(execute_data, return_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fuzzer_init_php_for_execute(const char *extra_ini) {
|
||||||
|
/* Compilation will often trigger fatal errors.
|
||||||
|
* Use tracked allocation mode to avoid leaks in that case. */
|
||||||
|
putenv("USE_TRACKED_ALLOC=1");
|
||||||
|
|
||||||
|
/* Just like other SAPIs, ignore SIGPIPEs. */
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
fuzzer_init_php(extra_ini);
|
||||||
|
|
||||||
|
zend_execute_ex = fuzzer_execute_ex;
|
||||||
|
orig_execute_internal = zend_execute_internal ? zend_execute_internal : execute_internal;
|
||||||
|
zend_execute_internal = fuzzer_execute_internal;
|
||||||
|
orig_compile_string = zend_compile_string;
|
||||||
|
zend_compile_string = fuzzer_compile_string;
|
||||||
|
}
|
|
@ -14,70 +14,7 @@
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <main/php.h>
|
#include "fuzzer-execute-common.h"
|
||||||
|
|
||||||
#include "fuzzer.h"
|
|
||||||
#include "fuzzer-sapi.h"
|
|
||||||
|
|
||||||
#define MAX_STEPS 1000
|
|
||||||
#define MAX_SIZE (8 * 1024)
|
|
||||||
static uint32_t steps_left;
|
|
||||||
|
|
||||||
/* Because the fuzzer is always compiled with clang,
|
|
||||||
* we can assume that we don't use global registers / hybrid VM. */
|
|
||||||
typedef int (ZEND_FASTCALL *opcode_handler_t)(zend_execute_data *);
|
|
||||||
|
|
||||||
static zend_always_inline void fuzzer_step(void) {
|
|
||||||
if (--steps_left == 0) {
|
|
||||||
/* Reset steps before bailing out, so code running after bailout (e.g. in
|
|
||||||
* destructors) will get another MAX_STEPS, rather than UINT32_MAX steps. */
|
|
||||||
steps_left = MAX_STEPS;
|
|
||||||
zend_bailout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fuzzer_execute_ex(zend_execute_data *execute_data) {
|
|
||||||
while (1) {
|
|
||||||
int ret;
|
|
||||||
fuzzer_step();
|
|
||||||
if ((ret = ((opcode_handler_t) EX(opline)->handler)(execute_data)) != 0) {
|
|
||||||
if (ret > 0) {
|
|
||||||
execute_data = EG(current_execute_data);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static zend_op_array *(*orig_compile_string)(zend_string *source_string, const char *filename);
|
|
||||||
|
|
||||||
static zend_op_array *fuzzer_compile_string(zend_string *str, const char *filename) {
|
|
||||||
if (ZSTR_LEN(str) > MAX_SIZE) {
|
|
||||||
/* Avoid compiling huge inputs via eval(). */
|
|
||||||
zend_bailout();
|
|
||||||
}
|
|
||||||
|
|
||||||
return orig_compile_string(str, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void (*orig_execute_internal)(zend_execute_data *execute_data, zval *return_value);
|
|
||||||
|
|
||||||
static void fuzzer_execute_internal(zend_execute_data *execute_data, zval *return_value) {
|
|
||||||
fuzzer_step();
|
|
||||||
|
|
||||||
uint32_t num_args = ZEND_CALL_NUM_ARGS(execute_data);
|
|
||||||
for (uint32_t i = 0; i < num_args; i++) {
|
|
||||||
/* Some internal functions like preg_replace() may be slow on large inputs.
|
|
||||||
* Limit the maximum size of string inputs. */
|
|
||||||
zval *arg = ZEND_CALL_VAR_NUM(execute_data, i);
|
|
||||||
if (Z_TYPE_P(arg) == IS_STRING && Z_STRLEN_P(arg) > MAX_SIZE) {
|
|
||||||
zend_bailout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orig_execute_internal(execute_data, return_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
if (Size > MAX_SIZE) {
|
if (Size > MAX_SIZE) {
|
||||||
|
@ -87,27 +24,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
steps_left = MAX_STEPS;
|
steps_left = MAX_STEPS;
|
||||||
fuzzer_do_request_from_buffer("/fuzzer.php", (const char *) Data, Size, /* execute */ 1);
|
fuzzer_do_request_from_buffer(
|
||||||
|
"/fuzzer.php", (const char *) Data, Size, /* execute */ 1, /* before_shutdown */ NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
/* Compilation will often trigger fatal errors.
|
fuzzer_init_php_for_execute(NULL);
|
||||||
* Use tracked allocation mode to avoid leaks in that case. */
|
|
||||||
putenv("USE_TRACKED_ALLOC=1");
|
|
||||||
|
|
||||||
/* Just like other SAPIs, ignore SIGPIPEs. */
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
|
||||||
|
|
||||||
fuzzer_init_php();
|
|
||||||
|
|
||||||
zend_execute_ex = fuzzer_execute_ex;
|
|
||||||
orig_execute_internal = zend_execute_internal ? zend_execute_internal : execute_internal;
|
|
||||||
zend_execute_internal = fuzzer_execute_internal;
|
|
||||||
orig_compile_string = zend_compile_string;
|
|
||||||
zend_compile_string = fuzzer_compile_string;
|
|
||||||
|
|
||||||
/* fuzzer_shutdown_php(); */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
fuzzer_init_php();
|
fuzzer_init_php(NULL);
|
||||||
|
|
||||||
/* fuzzer_shutdown_php(); */
|
/* fuzzer_shutdown_php(); */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
86
sapi/fuzzer/fuzzer-jit.c
Normal file
86
sapi/fuzzer/fuzzer-jit.c
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| 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: Nikita Popov <nikic@php.net> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fuzzer-execute-common.h"
|
||||||
|
#include "zend_exceptions.h"
|
||||||
|
|
||||||
|
static void opcache_invalidate(void) {
|
||||||
|
steps_left = MAX_STEPS;
|
||||||
|
zend_exception_save();
|
||||||
|
zval retval, func, args[2];
|
||||||
|
ZVAL_STRING(&func, "opcache_invalidate");
|
||||||
|
ZVAL_STRING(&args[0], "/fuzzer.php");
|
||||||
|
ZVAL_TRUE(&args[1]);
|
||||||
|
call_user_function(CG(function_table), NULL, &func, &retval, 2, args);
|
||||||
|
ZEND_ASSERT(Z_TYPE(retval) == IS_TRUE);
|
||||||
|
zval_ptr_dtor(&args[0]);
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
zval_ptr_dtor(&func);
|
||||||
|
zend_exception_restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
if (Size > MAX_SIZE) {
|
||||||
|
/* Large inputs have a large impact on fuzzer performance,
|
||||||
|
* but are unlikely to be necessary to reach new codepaths. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_string *jit_option = zend_string_init("opcache.jit", sizeof("opcache.jit") - 1, 1);
|
||||||
|
|
||||||
|
/* First run without JIT to determine whether we bail out. We should not run JITed code if
|
||||||
|
* we bail out here, as the JIT code may loop infinitely. */
|
||||||
|
steps_left = MAX_STEPS;
|
||||||
|
bailed_out = false;
|
||||||
|
zend_alter_ini_entry_chars(
|
||||||
|
jit_option, "off", sizeof("off")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
|
||||||
|
fuzzer_do_request_from_buffer(
|
||||||
|
"/fuzzer.php", (const char *) Data, Size, /* execute */ 1, opcache_invalidate);
|
||||||
|
|
||||||
|
if (!bailed_out) {
|
||||||
|
steps_left = MAX_STEPS;
|
||||||
|
zend_alter_ini_entry_chars(jit_option,
|
||||||
|
"function", sizeof("function")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
|
||||||
|
fuzzer_do_request_from_buffer(
|
||||||
|
"/fuzzer.php", (const char *) Data, Size, /* execute */ 1, opcache_invalidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_string_release(jit_option);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_opcache_path(void) {
|
||||||
|
// TODO: Make this more general.
|
||||||
|
char *opcache_path = "modules/opcache.so";
|
||||||
|
return realpath(opcache_path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
|
char *opcache_path = get_opcache_path();
|
||||||
|
assert(opcache_path && "Failed to determine opcache path");
|
||||||
|
|
||||||
|
char ini_buf[256];
|
||||||
|
snprintf(ini_buf, sizeof(ini_buf),
|
||||||
|
"zend_extension=%s\n"
|
||||||
|
"opcache.validate_timestamps=0\n"
|
||||||
|
"opcache.file_update_protection=0\n"
|
||||||
|
"opcache.jit_buffer_size=512M",
|
||||||
|
opcache_path);
|
||||||
|
free(opcache_path);
|
||||||
|
fuzzer_init_php_for_execute(ini_buf);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -55,7 +55,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
fuzzer_init_php();
|
fuzzer_init_php(NULL);
|
||||||
|
|
||||||
/* fuzzer_shutdown_php(); */
|
/* fuzzer_shutdown_php(); */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -68,7 +68,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
fuzzer_init_php();
|
fuzzer_init_php(NULL);
|
||||||
|
|
||||||
/* The default parse depth limit allows stack overflows under asan. */
|
/* The default parse depth limit allows stack overflows under asan. */
|
||||||
onig_set_parse_depth_limit(512);
|
onig_set_parse_depth_limit(512);
|
||||||
|
|
|
@ -32,7 +32,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fuzzer_do_request_from_buffer("fuzzer.php", (const char *) Data, Size, /* execute */ 0);
|
fuzzer_do_request_from_buffer(
|
||||||
|
"fuzzer.php", (const char *) Data, Size, /* execute */ 0, /* before_shutdown */ NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +43,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
* Use tracked allocation mode to avoid leaks in that case. */
|
* Use tracked allocation mode to avoid leaks in that case. */
|
||||||
putenv("USE_TRACKED_ALLOC=1");
|
putenv("USE_TRACKED_ALLOC=1");
|
||||||
|
|
||||||
fuzzer_init_php();
|
fuzzer_init_php(NULL);
|
||||||
|
|
||||||
/* fuzzer_shutdown_php(); */
|
/* fuzzer_shutdown_php(); */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -131,7 +131,7 @@ static sapi_module_struct fuzzer_module = {
|
||||||
STANDARD_SAPI_MODULE_PROPERTIES
|
STANDARD_SAPI_MODULE_PROPERTIES
|
||||||
};
|
};
|
||||||
|
|
||||||
int fuzzer_init_php()
|
int fuzzer_init_php(const char *extra_ini)
|
||||||
{
|
{
|
||||||
#ifdef __SANITIZE_ADDRESS__
|
#ifdef __SANITIZE_ADDRESS__
|
||||||
/* We're going to leak all the memory allocated during startup,
|
/* We're going to leak all the memory allocated during startup,
|
||||||
|
@ -142,8 +142,20 @@ int fuzzer_init_php()
|
||||||
sapi_startup(&fuzzer_module);
|
sapi_startup(&fuzzer_module);
|
||||||
fuzzer_module.phpinfo_as_text = 1;
|
fuzzer_module.phpinfo_as_text = 1;
|
||||||
|
|
||||||
fuzzer_module.ini_entries = malloc(sizeof(HARDCODED_INI));
|
size_t ini_len = sizeof(HARDCODED_INI);
|
||||||
memcpy(fuzzer_module.ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI));
|
size_t extra_ini_len = extra_ini ? strlen(extra_ini) : 0;
|
||||||
|
if (extra_ini) {
|
||||||
|
ini_len += extra_ini_len + 1;
|
||||||
|
}
|
||||||
|
char *p = fuzzer_module.ini_entries = malloc(ini_len + 1);
|
||||||
|
memcpy(p, HARDCODED_INI, sizeof(HARDCODED_INI) - 1);
|
||||||
|
p += sizeof(HARDCODED_INI) - 1;
|
||||||
|
if (extra_ini) {
|
||||||
|
*p++ = '\n';
|
||||||
|
memcpy(p, extra_ini, extra_ini_len);
|
||||||
|
p += extra_ini_len;
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: we might want to test both Zend and malloc MM, but testing with malloc
|
* TODO: we might want to test both Zend and malloc MM, but testing with malloc
|
||||||
|
@ -230,7 +242,8 @@ int fuzzer_shutdown_php(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuzzer_do_request_from_buffer(
|
int fuzzer_do_request_from_buffer(
|
||||||
char *filename, const char *data, size_t data_len, bool execute)
|
char *filename, const char *data, size_t data_len, bool execute,
|
||||||
|
void (*before_shutdown)(void))
|
||||||
{
|
{
|
||||||
int retval = FAILURE; /* failure by default */
|
int retval = FAILURE; /* failure by default */
|
||||||
|
|
||||||
|
@ -253,6 +266,8 @@ int fuzzer_do_request_from_buffer(
|
||||||
file_handle.primary_script = 1;
|
file_handle.primary_script = 1;
|
||||||
file_handle.buf = estrndup(data, data_len);
|
file_handle.buf = estrndup(data, data_len);
|
||||||
file_handle.len = data_len;
|
file_handle.len = data_len;
|
||||||
|
/* Avoid ZEND_HANDLE_FILENAME for opcache. */
|
||||||
|
file_handle.type = ZEND_HANDLE_STREAM;
|
||||||
|
|
||||||
zend_op_array *op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
|
zend_op_array *op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
|
||||||
zend_destroy_file_handle(&file_handle);
|
zend_destroy_file_handle(&file_handle);
|
||||||
|
@ -267,6 +282,9 @@ int fuzzer_do_request_from_buffer(
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
|
||||||
CG(compiled_filename) = NULL; /* ??? */
|
CG(compiled_filename) = NULL; /* ??? */
|
||||||
|
if (before_shutdown) {
|
||||||
|
before_shutdown();
|
||||||
|
}
|
||||||
fuzzer_request_shutdown();
|
fuzzer_request_shutdown();
|
||||||
|
|
||||||
return (retval == SUCCESS) ? SUCCESS : FAILURE;
|
return (retval == SUCCESS) ? SUCCESS : FAILURE;
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int fuzzer_init_php(void);
|
int fuzzer_init_php(const char *extra_ini);
|
||||||
int fuzzer_request_startup(void);
|
int fuzzer_request_startup(void);
|
||||||
void fuzzer_request_shutdown(void);
|
void fuzzer_request_shutdown(void);
|
||||||
void fuzzer_setup_dummy_frame(void);
|
void fuzzer_setup_dummy_frame(void);
|
||||||
void fuzzer_call_php_func(const char *func_name, int nargs, char **params);
|
void fuzzer_call_php_func(const char *func_name, int nargs, char **params);
|
||||||
void fuzzer_call_php_func_zval(const char *func_name, int nargs, zval *args);
|
void fuzzer_call_php_func_zval(const char *func_name, int nargs, zval *args);
|
||||||
int fuzzer_do_request_from_buffer(
|
int fuzzer_do_request_from_buffer(
|
||||||
char *filename, const char *data, size_t data_len, bool execute);
|
char *filename, const char *data, size_t data_len, bool execute,
|
||||||
|
void (*before_shutdown)(void));
|
||||||
|
|
|
@ -60,7 +60,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
fuzzer_init_php();
|
fuzzer_init_php(NULL);
|
||||||
|
|
||||||
/* fuzzer_shutdown_php(); */
|
/* fuzzer_shutdown_php(); */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -75,7 +75,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t FullSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||||
fuzzer_init_php();
|
fuzzer_init_php(NULL);
|
||||||
|
|
||||||
/* fuzzer_shutdown_php(); */
|
/* fuzzer_shutdown_php(); */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue