mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Add fuzzer for tracing jit
This commit is contained in:
parent
e69fb48ea3
commit
06a25c774d
6 changed files with 117 additions and 27 deletions
|
@ -8,8 +8,11 @@ $(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)
|
||||
$(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-function-jit: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_FUNCTION_JIT_OBJS)
|
||||
$(FUZZER_BUILD) $(PHP_FUZZER_FUNCTION_JIT_OBJS) -o $@
|
||||
|
||||
$(SAPI_FUZZER_PATH)/php-fuzz-tracing-jit: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_TRACING_JIT_OBJS)
|
||||
$(FUZZER_BUILD) $(PHP_FUZZER_TRACING_JIT_OBJS) -o $@
|
||||
|
||||
$(SAPI_FUZZER_PATH)/php-fuzz-unserialize: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_UNSERIALIZE_OBJS)
|
||||
$(FUZZER_BUILD) $(PHP_FUZZER_UNSERIALIZE_OBJS) -o $@
|
||||
|
|
|
@ -30,7 +30,8 @@ When running `make` it creates these binaries in `sapi/fuzzer/`:
|
|||
* `php-fuzz-exif`: Fuzzing `exif_read_data()` function (requires --enable-exif)
|
||||
* `php-fuzz-mbstring`: Fuzzing `mb_ereg[i]()` (requires --enable-mbstring)
|
||||
* `php-fuzz-execute`: Fuzzing the executor
|
||||
* `php-fuzz-jit`: Fuzzing the function JIT (requires --enable-opcache)
|
||||
* `php-fuzz-function-jit`: Fuzzing the function JIT (requires --enable-opcache)
|
||||
* `php-fuzz-tracing-jit`: Fuzzing the tracing JIT (requires --enable-opcache)
|
||||
|
||||
Some fuzzers have a seed corpus in `sapi/fuzzer/corpus`. You can use it as follows:
|
||||
|
||||
|
@ -64,6 +65,13 @@ sapi/fuzzer/php-fuzz-parser -merge=1 ./my-parser-corpus sapi/fuzzer/corpus/parse
|
|||
sapi/fuzzer/php-fuzz-parser -only_ascii=1 ./my-parser-corpus
|
||||
```
|
||||
|
||||
For the execute, function-jit and tracing-jit fuzzers, a corpus may be generated from any set of test files:
|
||||
|
||||
```sh
|
||||
sapi/cli/php sapi/fuzzer/generate_execute_corpus.php ./execute-corpus Zend/tests ext/opcache/tests/jit
|
||||
sapi/fuzzer/php-fuzzer-function-jit ./execute-corpus
|
||||
```
|
||||
|
||||
For the mbstring fuzzer, you may want to build the libonig dependency with instrumentation. At this time, libonig is not clean under ubsan, so only the fuzzer and address sanitizers may be used.
|
||||
|
||||
```sh
|
||||
|
|
|
@ -54,7 +54,8 @@ if test "$PHP_FUZZER" != "no"; then
|
|||
|
||||
PHP_FUZZER_TARGET([parser], PHP_FUZZER_PARSER_OBJS)
|
||||
PHP_FUZZER_TARGET([execute], PHP_FUZZER_EXECUTE_OBJS)
|
||||
PHP_FUZZER_TARGET([jit], PHP_FUZZER_JIT_OBJS)
|
||||
PHP_FUZZER_TARGET([function-jit], PHP_FUZZER_FUNCTION_JIT_OBJS)
|
||||
PHP_FUZZER_TARGET([tracing-jit], PHP_FUZZER_TRACING_JIT_OBJS)
|
||||
PHP_FUZZER_TARGET([unserialize], PHP_FUZZER_UNSERIALIZE_OBJS)
|
||||
PHP_FUZZER_TARGET([unserializehash], PHP_FUZZER_UNSERIALIZEHASH_OBJS)
|
||||
PHP_FUZZER_TARGET([json], PHP_FUZZER_JSON_OBJS)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "fuzzer.h"
|
||||
#include "fuzzer-sapi.h"
|
||||
#include "zend_exceptions.h"
|
||||
|
||||
#define MAX_STEPS 1000
|
||||
#define MAX_SIZE (8 * 1024)
|
||||
|
@ -38,6 +39,8 @@ static zend_always_inline void fuzzer_step(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void (*orig_execute_ex)(zend_execute_data *execute_data);
|
||||
|
||||
static void fuzzer_execute_ex(zend_execute_data *execute_data) {
|
||||
while (1) {
|
||||
int ret;
|
||||
|
@ -91,9 +94,31 @@ static void fuzzer_init_php_for_execute(const char *extra_ini) {
|
|||
|
||||
fuzzer_init_php(extra_ini);
|
||||
|
||||
orig_execute_ex = zend_execute_ex;
|
||||
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;
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_UNUSED 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();
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_UNUSED char *get_opcache_path(void) {
|
||||
// TODO: Make this more general.
|
||||
char *opcache_path = "modules/opcache.so";
|
||||
return realpath(opcache_path, NULL);
|
||||
}
|
||||
|
|
|
@ -15,22 +15,6 @@
|
|||
*/
|
||||
|
||||
#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) {
|
||||
|
@ -63,12 +47,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
|||
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");
|
||||
|
@ -78,7 +56,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
|||
"zend_extension=%s\n"
|
||||
"opcache.validate_timestamps=0\n"
|
||||
"opcache.file_update_protection=0\n"
|
||||
"opcache.jit_buffer_size=512M",
|
||||
"opcache.jit_buffer_size=256M",
|
||||
opcache_path);
|
||||
free(opcache_path);
|
||||
fuzzer_init_php_for_execute(ini_buf);
|
75
sapi/fuzzer/fuzzer-tracing-jit.c
Normal file
75
sapi/fuzzer/fuzzer-tracing-jit.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
|
||||
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,
|
||||
"tracing", sizeof("tracing")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
|
||||
zend_execute_ex = orig_execute_ex;
|
||||
/* Trace & compile */
|
||||
fuzzer_do_request_from_buffer(
|
||||
"/fuzzer.php", (const char *) Data, Size, /* execute */ 1, NULL);
|
||||
/* Execute trace */
|
||||
fuzzer_do_request_from_buffer(
|
||||
"/fuzzer.php", (const char *) Data, Size, /* execute */ 1, opcache_invalidate);
|
||||
zend_execute_ex = fuzzer_execute_ex;
|
||||
}
|
||||
|
||||
zend_string_release(jit_option);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||
char *opcache_path = get_opcache_path();
|
||||
assert(opcache_path && "Failed to determine opcache path");
|
||||
|
||||
char ini_buf[512];
|
||||
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=256M\n"
|
||||
"opcache.jit_hot_func=1\n"
|
||||
"opcache.jit_hot_loop=1\n"
|
||||
"opcache.jit_hot_return=1\n"
|
||||
"opcache.jit_hot_side_exit=1\n"
|
||||
"opcache.jit_max_root_traces=32768",
|
||||
opcache_path);
|
||||
free(opcache_path);
|
||||
fuzzer_init_php_for_execute(ini_buf);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue