summaryrefslogtreecommitdiff
path: root/sapi/fuzzer/fuzzer-execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'sapi/fuzzer/fuzzer-execute.c')
-rw-r--r--sapi/fuzzer/fuzzer-execute.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/sapi/fuzzer/fuzzer-execute.c b/sapi/fuzzer/fuzzer-execute.c
new file mode 100644
index 0000000000..1259acb31e
--- /dev/null
+++ b/sapi/fuzzer/fuzzer-execute.c
@@ -0,0 +1,90 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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: |
+ | http://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;
+
+/* 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 void fuzzer_execute_ex(zend_execute_data *execute_data) {
+ while (1) {
+ int ret;
+ 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();
+ }
+
+ 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);
+}
+
+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;
+ }
+
+ steps_left = MAX_STEPS;
+ fuzzer_do_request_from_buffer("/fuzzer.php", (const char *) Data, Size, /* execute */ 1);
+
+ return 0;
+}
+
+int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ /* 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();
+
+ zend_execute_ex = fuzzer_execute_ex;
+ orig_compile_string = zend_compile_string;
+ zend_compile_string = fuzzer_compile_string;
+
+ /* fuzzer_shutdown_php(); */
+ return 0;
+}