1 /*
2 american fuzzy lop++ - custom mutators related routines
3 -------------------------------------------------------
4
5 Originally written by Shengtuo Hu
6
7 Now maintained by Marc Heuse <[email protected]>,
8 Heiko Eißfeldt <[email protected]> and
9 Andrea Fioraldi <[email protected]>
10 Dominik Maier <[email protected]>
11
12 Copyright 2016, 2017 Google Inc. All rights reserved.
13 Copyright 2019-2024 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 if (memchr(fn, '/', strlen(fn))) {
183
184 mutator->name_short = strdup(strrchr(fn, '/') + 1);
185
186 } else {
187
188 mutator->name_short = strdup(fn);
189
190 }
191
192 if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; }
193
194 mutator->name = fn;
195 ACTF("Loading custom mutator library from '%s'...", fn);
196
197 dh = dlopen(fn, RTLD_NOW);
198 if (!dh) FATAL("%s", dlerror());
199 mutator->dh = dh;
200
201 /* Mutator */
202 /* "afl_custom_init", optional for backward compatibility */
203 mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
204 if (!mutator->afl_custom_init) {
205
206 FATAL("Symbol 'afl_custom_init' not found.");
207
208 }
209
210 /* "afl_custom_fuzz" or "afl_custom_mutator", required */
211 mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
212 if (!mutator->afl_custom_fuzz) {
213
214 /* Try "afl_custom_mutator" for backward compatibility */
215 WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
216
217 mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
218 if (!mutator->afl_custom_fuzz) {
219
220 WARNF("Symbol 'afl_custom_mutator' not found.");
221
222 } else {
223
224 OKF("Found 'afl_custom_mutator'.");
225
226 }
227
228 } else {
229
230 OKF("Found 'afl_custom_mutator'.");
231
232 }
233
234 /* "afl_custom_introspection", optional */
235 #ifdef INTROSPECTION
236 mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
237 if (!mutator->afl_custom_introspection) {
238
239 ACTF("optional symbol 'afl_custom_introspection' not found.");
240
241 } else {
242
243 OKF("Found 'afl_custom_introspection'.");
244
245 }
246
247 #endif
248
249 /* "afl_custom_fuzz_count", optional */
250 mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
251 if (!mutator->afl_custom_fuzz_count) {
252
253 ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
254
255 } else {
256
257 OKF("Found 'afl_custom_fuzz_count'.");
258
259 }
260
261 /* "afl_custom_deinit", optional for backward compatibility */
262 mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
263 if (!mutator->afl_custom_deinit) {
264
265 FATAL("Symbol 'afl_custom_deinit' not found.");
266
267 }
268
269 /* "afl_custom_post_process", optional */
270 mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
271 if (!mutator->afl_custom_post_process) {
272
273 ACTF("optional symbol 'afl_custom_post_process' not found.");
274
275 } else {
276
277 OKF("Found 'afl_custom_post_process'.");
278
279 }
280
281 u8 notrim = 0;
282 /* "afl_custom_init_trim", optional */
283 mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
284 if (!mutator->afl_custom_init_trim) {
285
286 notrim = 1;
287 ACTF("optional symbol 'afl_custom_init_trim' not found.");
288
289 } else {
290
291 OKF("Found 'afl_custom_init_trim'.");
292
293 }
294
295 /* "afl_custom_trim", optional */
296 mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
297 if (!mutator->afl_custom_trim) {
298
299 notrim = 1;
300 ACTF("optional symbol 'afl_custom_trim' not found.");
301
302 } else {
303
304 OKF("Found 'afl_custom_trim'.");
305
306 }
307
308 /* "afl_custom_post_trim", optional */
309 mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
310 if (!mutator->afl_custom_post_trim) {
311
312 notrim = 1;
313 ACTF("optional symbol 'afl_custom_post_trim' not found.");
314
315 } else {
316
317 OKF("Found 'afl_custom_post_trim'.");
318
319 }
320
321 if (notrim) {
322
323 if (mutator->afl_custom_init_trim || mutator->afl_custom_trim ||
324 mutator->afl_custom_post_trim) {
325
326 WARNF(
327 "Custom mutator does not implement all three trim APIs, standard "
328 "trimming will be used.");
329
330 }
331
332 mutator->afl_custom_init_trim = NULL;
333 mutator->afl_custom_trim = NULL;
334 mutator->afl_custom_post_trim = NULL;
335
336 }
337
338 /* "afl_custom_havoc_mutation", optional */
339 mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
340 if (!mutator->afl_custom_havoc_mutation) {
341
342 ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
343
344 } else {
345
346 OKF("Found 'afl_custom_havoc_mutation'.");
347
348 }
349
350 /* "afl_custom_havoc_mutation", optional */
351 mutator->afl_custom_havoc_mutation_probability =
352 dlsym(dh, "afl_custom_havoc_mutation_probability");
353 if (!mutator->afl_custom_havoc_mutation_probability) {
354
355 ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
356
357 } else {
358
359 OKF("Found 'afl_custom_havoc_mutation_probability'.");
360
361 }
362
363 /* "afl_custom_queue_get", optional */
364 mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
365 if (!mutator->afl_custom_queue_get) {
366
367 ACTF("optional symbol 'afl_custom_queue_get' not found.");
368
369 } else {
370
371 OKF("Found 'afl_custom_queue_get'.");
372
373 }
374
375 /* "afl_custom_splice_optout", optional, never called */
376 mutator->afl_custom_splice_optout = dlsym(dh, "afl_custom_splice_optout");
377 if (!mutator->afl_custom_splice_optout) {
378
379 ACTF("optional symbol 'afl_custom_splice_optout' not found.");
380
381 } else {
382
383 OKF("Found 'afl_custom_splice_optout'.");
384 afl->custom_splice_optout = 1;
385
386 }
387
388 /* "afl_custom_fuzz_send", optional */
389 mutator->afl_custom_fuzz_send = dlsym(dh, "afl_custom_fuzz_send");
390 if (!mutator->afl_custom_fuzz_send) {
391
392 ACTF("optional symbol 'afl_custom_fuzz_send' not found.");
393
394 } else {
395
396 OKF("Found 'afl_custom_fuzz_send'.");
397
398 }
399
400 /* "afl_custom_post_run", optional */
401 mutator->afl_custom_post_run = dlsym(dh, "afl_custom_post_run");
402 if (!mutator->afl_custom_post_run) {
403
404 ACTF("optional symbol 'afl_custom_post_run' not found.");
405
406 } else {
407
408 OKF("Found 'afl_custom_post_run'.");
409
410 }
411
412 /* "afl_custom_queue_new_entry", optional */
413 mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
414 if (!mutator->afl_custom_queue_new_entry) {
415
416 ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
417
418 } else {
419
420 OKF("Found 'afl_custom_queue_new_entry'.");
421
422 }
423
424 /* "afl_custom_describe", optional */
425 mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe");
426 if (!mutator->afl_custom_describe) {
427
428 ACTF("optional symbol 'afl_custom_describe' not found.");
429
430 } else {
431
432 OKF("Found 'afl_custom_describe'.");
433
434 }
435
436 OKF("Custom mutator '%s' installed successfully.", fn);
437
438 /* Initialize the custom mutator */
439 if (mutator->afl_custom_init) {
440
441 mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
442
443 }
444
445 mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
446 mutator->stacked_custom_prob =
447 6; // like one of the default mutations in havoc
448
449 return mutator;
450
451 }
452
trim_case_custom(afl_state_t * afl,struct queue_entry * q,u8 * in_buf,struct custom_mutator * mutator)453 u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
454 struct custom_mutator *mutator) {
455
456 u8 fault = 0;
457 u32 trim_exec = 0;
458 u32 orig_len = q->len;
459 u32 out_len = 0;
460 u8 *out_buf = NULL;
461
462 u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
463
464 afl->stage_name = afl->stage_name_buf;
465 afl->bytes_trim_in += q->len;
466
467 /* Initialize trimming in the custom mutator */
468 afl->stage_cur = 0;
469 s32 retval = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len);
470 if (unlikely(retval) < 0) {
471
472 FATAL("custom_init_trim error ret: %d", retval);
473
474 } else {
475
476 afl->stage_max = retval;
477
478 }
479
480 if (afl->not_on_tty && afl->debug) {
481
482 SAYF("[Custom Trimming] START: Max %u iterations, %u bytes", afl->stage_max,
483 q->len);
484
485 }
486
487 while (afl->stage_cur < afl->stage_max) {
488
489 u8 *retbuf = NULL;
490
491 sprintf(afl->stage_name_buf, "ptrim %s",
492 u_stringify_int(val_buf, trim_exec));
493
494 u64 cksum;
495
496 size_t retlen = mutator->afl_custom_trim(mutator->data, &retbuf);
497
498 if (unlikely(!retbuf)) {
499
500 FATAL("custom_trim failed (ret %zu)", retlen);
501
502 } else if (unlikely(retlen > orig_len)) {
503
504 /* Do not exit the fuzzer, even if the trimmed data returned by the custom
505 mutator is larger than the original data. For some use cases, like the
506 grammar mutator, the definition of "size" may have different meanings.
507 For example, the trimming function in a grammar mutator aims at
508 reducing the objects in a grammar structure, but does not guarantee to
509 generate a smaller binary buffer.
510
511 Thus, we allow the custom mutator to generate the trimmed data that is
512 larger than the original data. */
513
514 if (afl->not_on_tty && afl->debug) {
515
516 WARNF(
517 "Trimmed data returned by custom mutator is larger than original "
518 "data");
519
520 }
521
522 } else if (unlikely(retlen == 0)) {
523
524 /* Do not run the empty test case on the target. To keep the custom
525 trimming function running, we simply treat the empty test case as an
526 unsuccessful trimming and skip it, instead of aborting the trimming. */
527
528 ++afl->trim_execs;
529
530 }
531
532 if (likely(retlen)) {
533
534 retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0);
535
536 if (unlikely(!retlen)) {
537
538 ++afl->trim_execs;
539
540 } else {
541
542 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
543 ++afl->trim_execs;
544
545 if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
546
547 classify_counts(&afl->fsrv);
548 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
549
550 }
551
552 }
553
554 if (likely(retlen && cksum == q->exec_cksum)) {
555
556 /* Let's save a clean trace, which will be needed by
557 update_bitmap_score once we're done with the trimming stuff.
558 Use out_buf NULL check to make this only happen once per trim. */
559
560 if (!out_buf) {
561
562 memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
563 afl->fsrv.map_size);
564
565 }
566
567 if (afl_realloc((void **)&out_buf, retlen) == NULL) {
568
569 FATAL("can not allocate memory for trim");
570
571 }
572
573 out_len = retlen;
574 // TODO are we sure that retbuf fits into out_buf if retbuf can actually
575 // increase in size?
576 memcpy(out_buf, retbuf, retlen);
577
578 /* Tell the custom mutator that the trimming was successful */
579 afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
580
581 if (afl->not_on_tty && afl->debug) {
582
583 SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)",
584 afl->stage_cur, afl->stage_max, out_len);
585
586 }
587
588 } else {
589
590 /* Tell the custom mutator that the trimming was unsuccessful */
591 s32 retval2 = mutator->afl_custom_post_trim(mutator->data, 0);
592 if (unlikely(retval2 < 0)) {
593
594 FATAL("Error ret in custom_post_trim: %d", retval2);
595
596 } else {
597
598 afl->stage_cur = retval2;
599
600 }
601
602 if (afl->not_on_tty && afl->debug) {
603
604 SAYF("[Custom Trimming] FAILURE: %u/%u iterations", afl->stage_cur,
605 afl->stage_max);
606
607 }
608
609 }
610
611 /* Since this can be slow, update the screen every now and then. */
612
613 if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
614
615 }
616
617 /* If we have made changes, we also need to update the on-disk
618 version of the test case. */
619
620 if (out_buf) {
621
622 s32 fd;
623
624 unlink(q->fname); /* ignore errors */
625
626 fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
627
628 if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
629
630 ck_write(fd, out_buf, out_len, q->fname);
631 close(fd);
632
633 /* Update the queue's knowledge of length as soon as we write the file.
634 We do this here so that exit/error cases that *don't* update the file
635 also don't update q->len. */
636 q->len = out_len;
637
638 memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
639 update_bitmap_score(afl, q);
640
641 }
642
643 if (afl->not_on_tty && afl->debug) {
644
645 SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
646
647 }
648
649 abort_trimming:
650
651 if (out_buf) afl_free(out_buf);
652 afl->bytes_trim_out += q->len;
653 return fault;
654
655 }
656
657