• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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