1 /*
2 american fuzzy lop++ - afl-proxy skeleton example
3 ---------------------------------------------------
4
5 Written by Marc Heuse <[email protected]>
6
7 Copyright 2019-2024 AFLplusplus Project. All rights reserved.
8
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at:
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15
16 HOW-TO
17 ======
18
19 You only need to change the while() loop of the main() to send the
20 data of buf[] with length len to the target and write the coverage
21 information to __afl_area_ptr[__afl_map_size]
22
23
24 */
25
26 #ifdef __ANDROID__
27 #include "android-ashmem.h"
28 #endif
29 #include "config.h"
30 #include "types.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <stdint.h>
39 #include <errno.h>
40
41 #include <sys/mman.h>
42 #include <sys/shm.h>
43 #include <sys/wait.h>
44 #include <sys/types.h>
45 #include <fcntl.h>
46
47 u8 *__afl_area_ptr;
48
49 #ifdef __ANDROID__
50 u32 __afl_map_size = MAP_SIZE;
51 #else
52 __thread u32 __afl_map_size = MAP_SIZE;
53 #endif
54
55 /* Error reporting to forkserver controller */
56
send_forkserver_error(int error)57 void send_forkserver_error(int error) {
58
59 u32 status;
60 if (!error || error > 0xffff) return;
61 status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
62 if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
63
64 }
65
66 /* SHM setup. */
67
__afl_map_shm(void)68 static void __afl_map_shm(void) {
69
70 char *id_str = getenv(SHM_ENV_VAR);
71 char *ptr;
72
73 /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then
74 uncomment the following: */
75
76 /*
77 if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
78
79 u32 val = atoi(ptr);
80 if (val > 0) __afl_map_size = val;
81
82 }
83
84 */
85
86 if (__afl_map_size > MAP_SIZE) {
87
88 if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
89
90 fprintf(stderr,
91 "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
92 "be able to run this instrumented program!\n",
93 __afl_map_size);
94 if (id_str) {
95
96 send_forkserver_error(FS_ERROR_MAP_SIZE);
97 exit(-1);
98
99 }
100
101 } else {
102
103 fprintf(stderr,
104 "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
105 "be able to run this instrumented program!\n",
106 __afl_map_size);
107
108 }
109
110 }
111
112 if (id_str) {
113
114 #ifdef USEMMAP
115 const char *shm_file_path = id_str;
116 int shm_fd = -1;
117 unsigned char *shm_base = NULL;
118
119 /* create the shared memory segment as if it was a file */
120 shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
121 if (shm_fd == -1) {
122
123 fprintf(stderr, "shm_open() failed\n");
124 send_forkserver_error(FS_ERROR_SHM_OPEN);
125 exit(1);
126
127 }
128
129 /* map the shared memory segment to the address space of the process */
130 shm_base =
131 mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
132
133 if (shm_base == MAP_FAILED) {
134
135 close(shm_fd);
136 shm_fd = -1;
137
138 fprintf(stderr, "mmap() failed\n");
139 send_forkserver_error(FS_ERROR_MMAP);
140 exit(2);
141
142 }
143
144 __afl_area_ptr = shm_base;
145 #else
146 u32 shm_id = atoi(id_str);
147
148 __afl_area_ptr = shmat(shm_id, 0, 0);
149
150 #endif
151
152 if (__afl_area_ptr == (void *)-1) {
153
154 send_forkserver_error(FS_ERROR_SHMAT);
155 exit(1);
156
157 }
158
159 /* Write something into the bitmap so that the parent doesn't give up */
160
161 __afl_area_ptr[0] = 1;
162
163 }
164
165 }
166
167 /* Fork server logic. */
168
__afl_start_forkserver(void)169 static void __afl_start_forkserver(void) {
170
171 u8 tmp[4] = {0, 0, 0, 0};
172 u32 status = 0;
173
174 if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
175 status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
176 if (status) status |= (FS_OPT_ENABLED);
177 memcpy(tmp, &status, 4);
178
179 /* Phone home and tell the parent that we're OK. */
180
181 if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
182
183 }
184
__afl_next_testcase(u8 * buf,u32 max_len)185 static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
186
187 s32 status, res = 0xffffff;
188
189 /* Wait for parent by reading from the pipe. Abort if read fails. */
190 if (read(FORKSRV_FD, &status, 4) != 4) return 0;
191
192 /* we have a testcase - read it */
193 status = read(0, buf, max_len);
194
195 /* report that we are starting the target */
196 if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
197
198 return status;
199
200 }
201
__afl_end_testcase(void)202 static void __afl_end_testcase(void) {
203
204 int status = 0xffffff;
205
206 if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
207
208 }
209
210 /* you just need to modify the while() loop in this main() */
211
main(int argc,char * argv[])212 int main(int argc, char *argv[]) {
213
214 /* This is were the testcase data is written into */
215 u8 buf[1024]; // this is the maximum size for a test case! set it!
216 s32 len;
217
218 /* here you specify the map size you need that you are reporting to
219 afl-fuzz. Any value is fine as long as it can be divided by 32. */
220 __afl_map_size = MAP_SIZE; // default is 65536
221
222 /* then we initialize the shared memory map and start the forkserver */
223 __afl_map_shm();
224 __afl_start_forkserver();
225
226 while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
227
228 if (len > 4) { // the minimum data size you need for the target
229
230 /* here you have to create the magic that feeds the buf/len to the
231 target and write the coverage to __afl_area_ptr */
232
233 // ... the magic ...
234
235 // remove this, this is just to make afl-fuzz not complain when run
236 if (buf[0] == 0xff)
237 __afl_area_ptr[1] = 1;
238 else
239 __afl_area_ptr[2] = 2;
240
241 }
242
243 /* report the test case is done and wait for the next */
244 __afl_end_testcase();
245
246 }
247
248 return 0;
249
250 }
251
252