summaryrefslogtreecommitdiff
path: root/sapi/fuzzer/fuzzer-sapi.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-10-09 19:17:07 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-08-27 13:06:24 +0200
commitc29838c561fdd6903d2ad8a5fa6820c1f26ab3c9 (patch)
tree736ef03db71e398731a519345d4f739026068430 /sapi/fuzzer/fuzzer-sapi.c
parent988fc94bbbfb44a63ef5aeb745d38c1a73e2db0f (diff)
downloadphp-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.c94
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;