1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Nikita Popov <nikic@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include <main/php.h>
18
19 #include "fuzzer.h"
20 #include "fuzzer-sapi.h"
21
22 #define MAX_STEPS 1000
23 #define MAX_SIZE (8 * 1024)
24 static uint32_t steps_left;
25
26 /* Because the fuzzer is always compiled with clang,
27 * we can assume that we don't use global registers / hybrid VM. */
28 typedef int (ZEND_FASTCALL *opcode_handler_t)(zend_execute_data *);
29
fuzzer_execute_ex(zend_execute_data * execute_data)30 static void fuzzer_execute_ex(zend_execute_data *execute_data) {
31 while (1) {
32 int ret;
33 if (--steps_left == 0) {
34 /* Reset steps before bailing out, so code running after bailout (e.g. in
35 * destructors) will get another MAX_STEPS, rather than UINT32_MAX steps. */
36 steps_left = MAX_STEPS;
37 zend_bailout();
38 }
39
40 if ((ret = ((opcode_handler_t) EX(opline)->handler)(execute_data)) != 0) {
41 if (ret > 0) {
42 execute_data = EG(current_execute_data);
43 } else {
44 return;
45 }
46 }
47 }
48 }
49
50 static zend_op_array *(*orig_compile_string)(zend_string *source_string, const char *filename);
51
fuzzer_compile_string(zend_string * str,const char * filename)52 static zend_op_array *fuzzer_compile_string(zend_string *str, const char *filename) {
53 if (ZSTR_LEN(str) > MAX_SIZE) {
54 /* Avoid compiling huge inputs via eval(). */
55 zend_bailout();
56 }
57
58 return orig_compile_string(str, filename);
59 }
60
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)61 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
62 if (Size > MAX_SIZE) {
63 /* Large inputs have a large impact on fuzzer performance,
64 * but are unlikely to be necessary to reach new codepaths. */
65 return 0;
66 }
67
68 steps_left = MAX_STEPS;
69 fuzzer_do_request_from_buffer("/fuzzer.php", (const char *) Data, Size, /* execute */ 1);
70
71 return 0;
72 }
73
LLVMFuzzerInitialize(int * argc,char *** argv)74 int LLVMFuzzerInitialize(int *argc, char ***argv) {
75 /* Compilation will often trigger fatal errors.
76 * Use tracked allocation mode to avoid leaks in that case. */
77 putenv("USE_TRACKED_ALLOC=1");
78
79 /* Just like other SAPIs, ignore SIGPIPEs. */
80 signal(SIGPIPE, SIG_IGN);
81
82 fuzzer_init_php();
83
84 zend_execute_ex = fuzzer_execute_ex;
85 orig_compile_string = zend_compile_string;
86 zend_compile_string = fuzzer_compile_string;
87
88 /* fuzzer_shutdown_php(); */
89 return 0;
90 }
91