1 /*
2 american fuzzy lop++ - custom mutators related routines
3 -------------------------------------------------------
4
5 Originally written by Shengtuo Hu
6
7 Now maintained by Marc Heuse <mh@mh-sec.de>,
8 Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
9 Andrea Fioraldi <andreafioraldi@gmail.com>
10 Dominik Maier <mail@dmnk.co>
11
12 Copyright 2016, 2017 Google Inc. All rights reserved.
13 Copyright 2019-2022 AFLplusplus Project. All rights reserved.
14
15 Licensed under the Apache License, Version 2.0 (the "License");
16 you may not use this file except in compliance with the License.
17 You may obtain a copy of the License at:
18
19 https://www.apache.org/licenses/LICENSE-2.0
20
21 This is the real deal: the program takes an instrumented binary and
22 attempts a variety of basic fuzzing tricks, paying close attention to
23 how they affect the execution path.
24
25 */
26
27 #include "afl-fuzz.h"
28
29 struct custom_mutator *load_custom_mutator(afl_state_t *, const char *);
30 #ifdef USE_PYTHON
31 struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
32 #endif
33
run_afl_custom_queue_new_entry(afl_state_t * afl,struct queue_entry * q,u8 * fname,u8 * mother_fname)34 void run_afl_custom_queue_new_entry(afl_state_t *afl, struct queue_entry *q,
35 u8 *fname, u8 *mother_fname) {
36
37 if (afl->custom_mutators_count) {
38
39 u8 updated = 0;
40
41 LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
42
43 if (el->afl_custom_queue_new_entry) {
44
45 if (el->afl_custom_queue_new_entry(el->data, fname, mother_fname)) {
46
47 updated = 1;
48
49 }
50
51 }
52
53 });
54
55 if (updated) {
56
57 struct stat st;
58 if (stat(fname, &st)) { PFATAL("File %s is gone!", fname); }
59 if (!st.st_size) {
60
61 FATAL("File %s became empty in custom mutator!", fname);
62
63 }
64
65 q->len = st.st_size;
66
67 }
68
69 }
70
71 }
72
setup_custom_mutators(afl_state_t * afl)73 void setup_custom_mutators(afl_state_t *afl) {
74
75 /* Try mutator library first */
76 struct custom_mutator *mutator;
77 u8 * fn = afl->afl_env.afl_custom_mutator_library;
78 u32 prev_mutator_count = 0;
79
80 if (fn) {
81
82 if (afl->limit_time_sig && afl->limit_time_sig != -1)
83 FATAL(
84 "MOpt and custom mutator are mutually exclusive. We accept pull "
85 "requests that integrates MOpt with the optional mutators "
86 "(custom/redqueen/...).");
87
88 u8 *fn_token = (u8 *)strsep((char **)&fn, ";:,");
89
90 if (likely(!fn_token)) {
91
92 mutator = load_custom_mutator(afl, fn);
93 list_append(&afl->custom_mutator_list, mutator);
94 afl->custom_mutators_count++;
95
96 } else {
97
98 while (fn_token) {
99
100 if (*fn_token) { // strsep can be empty if ";;"
101
102 if (afl->not_on_tty && afl->debug)
103 SAYF("[Custom] Processing: %s\n", fn_token);
104 prev_mutator_count = afl->custom_mutators_count;
105 mutator = load_custom_mutator(afl, fn_token);
106 list_append(&afl->custom_mutator_list, mutator);
107 afl->custom_mutators_count++;
108 if (prev_mutator_count > afl->custom_mutators_count)
109 FATAL("Maximum Custom Mutator count reached.");
110 fn_token = (u8 *)strsep((char **)&fn, ";:,");
111
112 }
113
114 }
115
116 }
117
118 }
119
120 /* Try Python module */
121 #ifdef USE_PYTHON
122 u8 *module_name = afl->afl_env.afl_python_module;
123
124 if (module_name) {
125
126 if (afl->limit_time_sig) {
127
128 FATAL(
129 "MOpt and Python mutator are mutually exclusive. We accept pull "
130 "requests that integrates MOpt with the optional mutators "
131 "(custom/redqueen/...).");
132
133 }
134
135 struct custom_mutator *m = load_custom_mutator_py(afl, module_name);
136 afl->custom_mutators_count++;
137 list_append(&afl->custom_mutator_list, m);
138
139 }
140
141 #else
142 if (afl->afl_env.afl_python_module) {
143
144 FATAL("Your AFL binary was built without Python support");
145
146 }
147
148 #endif
149
150 }
151
destroy_custom_mutators(afl_state_t * afl)152 void destroy_custom_mutators(afl_state_t *afl) {
153
154 if (afl->custom_mutators_count) {
155
156 LIST_FOREACH_CLEAR(&afl->custom_mutator_list, struct custom_mutator, {
157
158 if (!el->data) { FATAL("Deintializing NULL mutator"); }
159 if (el->afl_custom_deinit) el->afl_custom_deinit(el->data);
160 if (el->dh) dlclose(el->dh);
161
162 if (el->post_process_buf) {
163
164 afl_free(el->post_process_buf);
165 el->post_process_buf = NULL;
166
167 }
168
169 ck_free(el);
170
171 });
172
173 }
174
175 }
176
load_custom_mutator(afl_state_t * afl,const char * fn)177 struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
178
179 void * dh;
180 struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
181
182 mutator->name = fn;
183 if (memchr(fn, '/', strlen(fn)))
184 mutator->name_short = strrchr(fn, '/') + 1;
185 else
186 mutator->name_short = strdup(fn);
187 ACTF("Loading custom mutator library from '%s'...", fn);
188
189 dh = dlopen(fn, RTLD_NOW);
190 if (!dh) FATAL("%s", dlerror());
191 mutator->dh = dh;
192
193 /* Mutator */
194 /* "afl_custom_init", optional for backward compatibility */
195 mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
196 if (!mutator->afl_custom_init) {
197
198 FATAL("Symbol 'afl_custom_init' not found.");
199
200 }
201
202 /* "afl_custom_fuzz" or "afl_custom_mutator", required */
203 mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
204 if (!mutator->afl_custom_fuzz) {
205
206 /* Try "afl_custom_mutator" for backward compatibility */
207 WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
208
209 mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
210 if (!mutator->afl_custom_fuzz) {
211
212 WARNF("Symbol 'afl_custom_mutator' not found.");
213
214 }
215
216 }
217
218 /* "afl_custom_introspection", optional */
219 #ifdef INTROSPECTION
220 mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
221 if (!mutator->afl_custom_introspection) {
222
223 ACTF("optional symbol 'afl_custom_introspection' not found.");
224
225 }
226
227 #endif
228
229 /* "afl_custom_fuzz_count", optional */
230 mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
231 if (!mutator->afl_custom_fuzz_count) {
232
233 ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
234
235 }
236
237 /* "afl_custom_deinit", optional for backward compatibility */
238 mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
239 if (!mutator->afl_custom_deinit) {
240
241 FATAL("Symbol 'afl_custom_deinit' not found.");
242
243 }
244
245 /* "afl_custom_post_process", optional */
246 mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
247 if (!mutator->afl_custom_post_process) {
248
249 ACTF("optional symbol 'afl_custom_post_process' not found.");
250
251 }
252
253 u8 notrim = 0;
254 /* "afl_custom_init_trim", optional */
255 mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
256 if (!mutator->afl_custom_init_trim) {
257
258 notrim = 1;
259 ACTF("optional symbol 'afl_custom_init_trim' not found.");
260
261 }
262
263 /* "afl_custom_trim", optional */
264 mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
265 if (!mutator->afl_custom_trim) {
266
267 notrim = 1;
268 ACTF("optional symbol 'afl_custom_trim' not found.");
269
270 }
271
272 /* "afl_custom_post_trim", optional */
273 mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
274 if (!mutator->afl_custom_post_trim) {
275
276 notrim = 1;
277 ACTF("optional symbol 'afl_custom_post_trim' not found.");
278
279 }
280
281 if (notrim) {
282
283 mutator->afl_custom_init_trim = NULL;
284 mutator->afl_custom_trim = NULL;
285 mutator->afl_custom_post_trim = NULL;
286 ACTF(
287 "Custom mutator does not implement all three trim APIs, standard "
288 "trimming will be used.");
289
290 }
291
292 /* "afl_custom_havoc_mutation", optional */
293 mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
294 if (!mutator->afl_custom_havoc_mutation) {
295
296 ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
297
298 }
299
300 /* "afl_custom_havoc_mutation", optional */
301 mutator->afl_custom_havoc_mutation_probability =
302 dlsym(dh, "afl_custom_havoc_mutation_probability");
303 if (!mutator->afl_custom_havoc_mutation_probability) {
304
305 ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
306
307 }
308
309 /* "afl_custom_queue_get", optional */
310 mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
311 if (!mutator->afl_custom_queue_get) {
312
313 ACTF("optional symbol 'afl_custom_queue_get' not found.");
314
315 }
316
317 /* "afl_custom_queue_new_entry", optional */
318 mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
319 if (!mutator->afl_custom_queue_new_entry) {
320
321 ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
322
323 }
324
325 /* "afl_custom_describe", optional */
326 mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe");
327 if (!mutator->afl_custom_describe) {
328
329 ACTF("Symbol 'afl_custom_describe' not found.");
330
331 }
332
333 OKF("Custom mutator '%s' installed successfully.", fn);
334
335 /* Initialize the custom mutator */
336 if (mutator->afl_custom_init) {
337
338 mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
339
340 }
341
342 mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
343 mutator->stacked_custom_prob =
344 6; // like one of the default mutations in havoc
345
346 return mutator;
347
348 }
349
trim_case_custom(afl_state_t * afl,struct queue_entry * q,u8 * in_buf,struct custom_mutator * mutator)350 u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
351 struct custom_mutator *mutator) {
352
353 u8 fault = 0;
354 u32 trim_exec = 0;
355 u32 orig_len = q->len;
356 u32 out_len = 0;
357 u8 *out_buf = NULL;
358
359 u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
360
361 afl->stage_name = afl->stage_name_buf;
362 afl->bytes_trim_in += q->len;
363
364 /* Initialize trimming in the custom mutator */
365 afl->stage_cur = 0;
366 s32 retval = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len);
367 if (unlikely(retval) < 0) {
368
369 FATAL("custom_init_trim error ret: %d", retval);
370
371 } else {
372
373 afl->stage_max = retval;
374
375 }
376
377 if (afl->not_on_tty && afl->debug) {
378
379 SAYF("[Custom Trimming] START: Max %u iterations, %u bytes", afl->stage_max,
380 q->len);
381
382 }
383
384 while (afl->stage_cur < afl->stage_max) {
385
386 u8 *retbuf = NULL;
387
388 sprintf(afl->stage_name_buf, "ptrim %s",
389 u_stringify_int(val_buf, trim_exec));
390
391 u64 cksum;
392
393 size_t retlen = mutator->afl_custom_trim(mutator->data, &retbuf);
394
395 if (unlikely(!retbuf)) {
396
397 FATAL("custom_trim failed (ret %zu)", retlen);
398
399 } else if (unlikely(retlen > orig_len)) {
400
401 /* Do not exit the fuzzer, even if the trimmed data returned by the custom
402 mutator is larger than the original data. For some use cases, like the
403 grammar mutator, the definition of "size" may have different meanings.
404 For example, the trimming function in a grammar mutator aims at
405 reducing the objects in a grammar structure, but does not guarantee to
406 generate a smaller binary buffer.
407
408 Thus, we allow the custom mutator to generate the trimmed data that is
409 larger than the original data. */
410
411 if (afl->not_on_tty && afl->debug) {
412
413 WARNF(
414 "Trimmed data returned by custom mutator is larger than original "
415 "data");
416
417 }
418
419 } else if (unlikely(retlen == 0)) {
420
421 /* Do not run the empty test case on the target. To keep the custom
422 trimming function running, we simply treat the empty test case as an
423 unsuccessful trimming and skip it, instead of aborting the trimming. */
424
425 ++afl->trim_execs;
426
427 }
428
429 if (likely(retlen)) {
430
431 retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0);
432
433 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
434 ++afl->trim_execs;
435
436 if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
437
438 classify_counts(&afl->fsrv);
439 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
440
441 }
442
443 if (likely(retlen && cksum == q->exec_cksum)) {
444
445 /* Let's save a clean trace, which will be needed by
446 update_bitmap_score once we're done with the trimming stuff.
447 Use out_buf NULL check to make this only happen once per trim. */
448
449 if (!out_buf) {
450
451 memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
452 afl->fsrv.map_size);
453
454 }
455
456 if (afl_realloc((void **)&out_buf, retlen) == NULL) {
457
458 FATAL("can not allocate memory for trim");
459
460 }
461
462 out_len = retlen;
463 // TODO are we sure that retbuf fits into out_buf if retbuf can actually
464 // increase in size?
465 memcpy(out_buf, retbuf, retlen);
466
467 /* Tell the custom mutator that the trimming was successful */
468 afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
469
470 if (afl->not_on_tty && afl->debug) {
471
472 SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)",
473 afl->stage_cur, afl->stage_max, out_len);
474
475 }
476
477 } else {
478
479 /* Tell the custom mutator that the trimming was unsuccessful */
480 s32 retval2 = mutator->afl_custom_post_trim(mutator->data, 0);
481 if (unlikely(retval2 < 0)) {
482
483 FATAL("Error ret in custom_post_trim: %d", retval2);
484
485 } else {
486
487 afl->stage_cur = retval2;
488
489 }
490
491 if (afl->not_on_tty && afl->debug) {
492
493 SAYF("[Custom Trimming] FAILURE: %u/%u iterations", afl->stage_cur,
494 afl->stage_max);
495
496 }
497
498 }
499
500 /* Since this can be slow, update the screen every now and then. */
501
502 if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
503
504 }
505
506 /* If we have made changes, we also need to update the on-disk
507 version of the test case. */
508
509 if (out_buf) {
510
511 s32 fd;
512
513 unlink(q->fname); /* ignore errors */
514
515 fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
516
517 if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
518
519 ck_write(fd, out_buf, out_len, q->fname);
520 close(fd);
521
522 /* Update the queue's knowledge of length as soon as we write the file.
523 We do this here so that exit/error cases that *don't* update the file
524 also don't update q->len. */
525 q->len = out_len;
526
527 memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
528 update_bitmap_score(afl, q);
529
530 }
531
532 if (afl->not_on_tty && afl->debug) {
533
534 SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
535
536 }
537
538 abort_trimming:
539
540 if (out_buf) afl_free(out_buf);
541 afl->bytes_trim_out += q->len;
542 return fault;
543
544 }
545
546