diff options
| author | Nikita Popov <nikita.ppv@gmail.com> | 2019-10-09 19:17:07 +0200 |
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-08-27 13:06:24 +0200 |
| commit | c29838c561fdd6903d2ad8a5fa6820c1f26ab3c9 (patch) | |
| tree | 736ef03db71e398731a519345d4f739026068430 /sapi/fuzzer/fuzzer-sapi.c | |
| parent | 988fc94bbbfb44a63ef5aeb745d38c1a73e2db0f (diff) | |
| download | php-git-c29838c561fdd6903d2ad8a5fa6820c1f26ab3c9.tar.gz | |
Add experimental "execute" fuzzer
This is an end-to-end fuzzer that executes arbitrary PHP code.
We replace the executor with a finite-step executor to avoid
getting stuck in loops or recursion.
Diffstat (limited to 'sapi/fuzzer/fuzzer-sapi.c')
| -rw-r--r-- | sapi/fuzzer/fuzzer-sapi.c | 94 |
1 files changed, 44 insertions, 50 deletions
diff --git a/sapi/fuzzer/fuzzer-sapi.c b/sapi/fuzzer/fuzzer-sapi.c index fdb4ff08b8..ff81073744 100644 --- a/sapi/fuzzer/fuzzer-sapi.c +++ b/sapi/fuzzer/fuzzer-sapi.c @@ -21,6 +21,7 @@ #include <ext/standard/info.h> #include <ext/standard/php_var.h> #include <main/php_variables.h> +#include <zend_exceptions.c> #ifdef __SANITIZE_ADDRESS__ # include "sanitizer/lsan_interface.h" @@ -34,9 +35,24 @@ const char HARDCODED_INI[] = "implicit_flush=1\n" "output_buffering=0\n" "error_reporting=0\n" + /* Let the timeout be enforced by libfuzzer, not PHP. */ + "max_execution_time=0\n" /* Reduce oniguruma limits to speed up fuzzing */ "mbstring.regex_stack_limit=10000\n" - "mbstring.regex_retry_limit=10000"; + "mbstring.regex_retry_limit=10000\n" + /* For the "execute" fuzzer disable some functions that are likely to have + * undesirable consequences (shell execution, file system writes). */ + "allow_url_include=0\n" + "allow_url_fopen=0\n" + "open_basedir=/tmp\n" + "disable_functions=dl,mail,mb_send_mail" + ",shell_exec,exec,system,proc_open,popen,passthru,pcntl_exec" + ",chgrp,chmod,chown,copy,file_put_contents,lchgrp,lchown,link,mkdir" + ",move_uploaded_file,rename,rmdir,symlink,tempname,touch,unlink,fopen" + ",fsockopen,stream_socket_pair,stream_socket_client" + /* openlog() has a known memory-management issue. */ + ",openlog" +; static int startup(sapi_module_struct *sapi_module) { @@ -158,16 +174,18 @@ int fuzzer_request_startup() void fuzzer_request_shutdown() { - /* Destroy thrown exceptions. This does not happen as part of request shutdown. */ - if (EG(exception)) { - zend_object_release(EG(exception)); - EG(exception) = NULL; - } + zend_try { + /* Destroy thrown exceptions. This does not happen as part of request shutdown. */ + if (EG(exception)) { + zend_object_release(EG(exception)); + EG(exception) = NULL; + } - /* Some fuzzers (like unserialize) may create circular structures. Make sure we free them. - * Two calls are performed to handle objects with destructors. */ - zend_gc_collect_cycles(); - zend_gc_collect_cycles(); + /* Some fuzzers (like unserialize) may create circular structures. Make sure we free them. + * Two calls are performed to handle objects with destructors. */ + zend_gc_collect_cycles(); + zend_gc_collect_cycles(); + } zend_end_try(); php_request_shutdown(NULL); } @@ -205,7 +223,8 @@ int fuzzer_shutdown_php() return SUCCESS; } -int fuzzer_do_request(zend_file_handle *file_handle, char *filename) +int fuzzer_do_request_from_buffer( + char *filename, const char *data, size_t data_len, zend_bool execute) { int retval = FAILURE; /* failure by default */ @@ -217,58 +236,33 @@ int fuzzer_do_request(zend_file_handle *file_handle, char *filename) return FAILURE; } - SG(headers_sent) = 1; - SG(request_info).no_headers = 1; + // Commented out to avoid leaking the header callback. + //SG(headers_sent) = 1; + //SG(request_info).no_headers = 1; php_register_variable("PHP_SELF", filename, NULL); zend_first_try { - zend_op_array *op_array = zend_compile_file(file_handle, ZEND_REQUIRE); + zend_file_handle file_handle; + zend_stream_init_filename(&file_handle, filename); + file_handle.buf = estrndup(data, data_len); + file_handle.len = data_len; + + zend_op_array *op_array = zend_compile_file(&file_handle, ZEND_REQUIRE); if (op_array) { + if (execute) { + zend_execute(op_array, NULL); + } destroy_op_array(op_array); efree(op_array); } - if (EG(exception)) { - zend_object_release(EG(exception)); - EG(exception) = NULL; - } - /*retval = php_execute_script(file_handle);*/ } zend_end_try(); - php_request_shutdown((void *) 0); + CG(compiled_filename) = NULL; /* ??? */ + fuzzer_request_shutdown(); return (retval == SUCCESS) ? SUCCESS : FAILURE; } - -int fuzzer_do_request_f(char *filename) -{ - zend_file_handle file_handle; - file_handle.type = ZEND_HANDLE_FILENAME; - file_handle.filename = filename; - file_handle.handle.fp = NULL; - file_handle.opened_path = NULL; - - return fuzzer_do_request(&file_handle, filename); -} - -int fuzzer_do_request_from_buffer(char *filename, char *data, size_t data_len) -{ - zend_file_handle file_handle; - file_handle.filename = filename; - file_handle.free_filename = 0; - file_handle.opened_path = NULL; - file_handle.handle.stream.handle = NULL; - file_handle.handle.stream.reader = (zend_stream_reader_t)_php_stream_read; - file_handle.handle.stream.fsizer = NULL; - file_handle.handle.stream.isatty = 0; - file_handle.handle.stream.closer = NULL; - file_handle.buf = data; - file_handle.len = data_len; - file_handle.type = ZEND_HANDLE_STREAM; - - return fuzzer_do_request(&file_handle, filename); -} - // Call named PHP function with N zval arguments void fuzzer_call_php_func_zval(const char *func_name, int nargs, zval *args) { zval retval, func; |
