xref: /aosp_15_r20/external/AFLplusplus/src/afl-fuzz-mutators.c (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
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