OLD | NEW |
(Empty) | |
| 1 /* |
| 2 american fuzzy lop - high-performance binary-only instrumentation |
| 3 ----------------------------------------------------------------- |
| 4 |
| 5 Written by Andrew Griffiths <agriffiths@google.com> and |
| 6 Michal Zalewski <lcamtuf@google.com> |
| 7 |
| 8 Idea & design very much by Andrew Griffiths. |
| 9 |
| 10 Copyright 2015, 2016 Google Inc. All rights reserved. |
| 11 |
| 12 Licensed under the Apache License, Version 2.0 (the "License"); |
| 13 you may not use this file except in compliance with the License. |
| 14 You may obtain a copy of the License at: |
| 15 |
| 16 http://www.apache.org/licenses/LICENSE-2.0 |
| 17 |
| 18 This code is a shim patched into the separately-distributed source |
| 19 code of QEMU 2.2.0. It leverages the built-in QEMU tracing functionality |
| 20 to implement AFL-style instrumentation and to take care of the remaining |
| 21 parts of the AFL fork server logic. |
| 22 |
| 23 The resulting QEMU binary is essentially a standalone instrumentation |
| 24 tool; for an example of how to leverage it for other purposes, you can |
| 25 have a look at afl-showmap.c. |
| 26 |
| 27 */ |
| 28 |
| 29 #include <sys/shm.h> |
| 30 #include "../../config.h" |
| 31 |
| 32 /*************************** |
| 33 * VARIOUS AUXILIARY STUFF * |
| 34 ***************************/ |
| 35 |
| 36 /* A snippet patched into tb_find_slow to inform the parent process that |
| 37 we have hit a new block that hasn't been translated yet, and to tell |
| 38 it to translate within its own context, too (this avoids translation |
| 39 overhead in the next forked-off copy). */ |
| 40 |
| 41 #define AFL_QEMU_CPU_SNIPPET1 do { \ |
| 42 afl_request_tsl(pc, cs_base, flags); \ |
| 43 } while (0) |
| 44 |
| 45 /* This snippet kicks in when the instruction pointer is positioned at |
| 46 _start and does the usual forkserver stuff, not very different from |
| 47 regular instrumentation injected via afl-as.h. */ |
| 48 |
| 49 #define AFL_QEMU_CPU_SNIPPET2 do { \ |
| 50 if(tb->pc == afl_entry_point) { \ |
| 51 afl_setup(); \ |
| 52 afl_forkserver(env); \ |
| 53 } \ |
| 54 afl_maybe_log(tb->pc); \ |
| 55 } while (0) |
| 56 |
| 57 /* We use one additional file descriptor to relay "needs translation" |
| 58 messages between the child and the fork server. */ |
| 59 |
| 60 #define TSL_FD (FORKSRV_FD - 1) |
| 61 |
| 62 /* This is equivalent to afl-as.h: */ |
| 63 |
| 64 static unsigned char *afl_area_ptr; |
| 65 |
| 66 /* Exported variables populated by the code patched into elfload.c: */ |
| 67 |
| 68 abi_ulong afl_entry_point, /* ELF entry point (_start) */ |
| 69 afl_start_code, /* .text start pointer */ |
| 70 afl_end_code; /* .text end pointer */ |
| 71 |
| 72 /* Set in the child process in forkserver mode: */ |
| 73 |
| 74 static unsigned char afl_fork_child; |
| 75 unsigned int afl_forksrv_pid; |
| 76 |
| 77 /* Instrumentation ratio: */ |
| 78 |
| 79 static unsigned int afl_inst_rms = MAP_SIZE; |
| 80 |
| 81 /* Function declarations. */ |
| 82 |
| 83 static void afl_setup(void); |
| 84 static void afl_forkserver(CPUArchState*); |
| 85 static inline void afl_maybe_log(abi_ulong); |
| 86 |
| 87 static void afl_wait_tsl(CPUArchState*, int); |
| 88 static void afl_request_tsl(target_ulong, target_ulong, uint64_t); |
| 89 |
| 90 static TranslationBlock *tb_find_slow(CPUArchState*, target_ulong, |
| 91 target_ulong, uint64_t); |
| 92 |
| 93 |
| 94 /* Data structure passed around by the translate handlers: */ |
| 95 |
| 96 struct afl_tsl { |
| 97 target_ulong pc; |
| 98 target_ulong cs_base; |
| 99 uint64_t flags; |
| 100 }; |
| 101 |
| 102 |
| 103 /************************* |
| 104 * ACTUAL IMPLEMENTATION * |
| 105 *************************/ |
| 106 |
| 107 |
| 108 /* Set up SHM region and initialize other stuff. */ |
| 109 |
| 110 static void afl_setup(void) { |
| 111 |
| 112 char *id_str = getenv(SHM_ENV_VAR), |
| 113 *inst_r = getenv("AFL_INST_RATIO"); |
| 114 |
| 115 int shm_id; |
| 116 |
| 117 if (inst_r) { |
| 118 |
| 119 unsigned int r; |
| 120 |
| 121 r = atoi(inst_r); |
| 122 |
| 123 if (r > 100) r = 100; |
| 124 if (!r) r = 1; |
| 125 |
| 126 afl_inst_rms = MAP_SIZE * r / 100; |
| 127 |
| 128 } |
| 129 |
| 130 if (id_str) { |
| 131 |
| 132 shm_id = atoi(id_str); |
| 133 afl_area_ptr = shmat(shm_id, NULL, 0); |
| 134 |
| 135 if (afl_area_ptr == (void*)-1) exit(1); |
| 136 |
| 137 /* With AFL_INST_RATIO set to a low value, we want to touch the bitmap |
| 138 so that the parent doesn't give up on us. */ |
| 139 |
| 140 if (inst_r) afl_area_ptr[0] = 1; |
| 141 |
| 142 |
| 143 } |
| 144 |
| 145 if (getenv("AFL_INST_LIBS")) { |
| 146 |
| 147 afl_start_code = 0; |
| 148 afl_end_code = (abi_ulong)-1; |
| 149 |
| 150 } |
| 151 |
| 152 } |
| 153 |
| 154 |
| 155 /* Fork server logic, invoked once we hit _start. */ |
| 156 |
| 157 static void afl_forkserver(CPUArchState *env) { |
| 158 |
| 159 static unsigned char tmp[4]; |
| 160 |
| 161 if (!afl_area_ptr) return; |
| 162 |
| 163 /* Tell the parent that we're alive. If the parent doesn't want |
| 164 to talk, assume that we're not running in forkserver mode. */ |
| 165 |
| 166 if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; |
| 167 |
| 168 afl_forksrv_pid = getpid(); |
| 169 |
| 170 /* All right, let's await orders... */ |
| 171 |
| 172 while (1) { |
| 173 |
| 174 pid_t child_pid; |
| 175 int status, t_fd[2]; |
| 176 |
| 177 /* Whoops, parent dead? */ |
| 178 |
| 179 if (read(FORKSRV_FD, tmp, 4) != 4) exit(2); |
| 180 |
| 181 /* Establish a channel with child to grab translation commands. We'll |
| 182 read from t_fd[0], child will write to TSL_FD. */ |
| 183 |
| 184 if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); |
| 185 close(t_fd[1]); |
| 186 |
| 187 child_pid = fork(); |
| 188 if (child_pid < 0) exit(4); |
| 189 |
| 190 if (!child_pid) { |
| 191 |
| 192 /* Child process. Close descriptors and run free. */ |
| 193 |
| 194 afl_fork_child = 1; |
| 195 close(FORKSRV_FD); |
| 196 close(FORKSRV_FD + 1); |
| 197 close(t_fd[0]); |
| 198 return; |
| 199 |
| 200 } |
| 201 |
| 202 /* Parent. */ |
| 203 |
| 204 close(TSL_FD); |
| 205 |
| 206 if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(5); |
| 207 |
| 208 /* Collect translation requests until child dies and closes the pipe. */ |
| 209 |
| 210 afl_wait_tsl(env, t_fd[0]); |
| 211 |
| 212 /* Get and relay exit status to parent. */ |
| 213 |
| 214 if (waitpid(child_pid, &status, 0) < 0) exit(6); |
| 215 if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); |
| 216 |
| 217 } |
| 218 |
| 219 } |
| 220 |
| 221 |
| 222 /* The equivalent of the tuple logging routine from afl-as.h. */ |
| 223 |
| 224 static inline void afl_maybe_log(abi_ulong cur_loc) { |
| 225 |
| 226 static __thread abi_ulong prev_loc; |
| 227 |
| 228 /* Optimize for cur_loc > afl_end_code, which is the most likely case on |
| 229 Linux systems. */ |
| 230 |
| 231 if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr) |
| 232 return; |
| 233 |
| 234 /* Looks like QEMU always maps to fixed locations, so ASAN is not a |
| 235 concern. Phew. But instruction addresses may be aligned. Let's mangle |
| 236 the value to get something quasi-uniform. */ |
| 237 |
| 238 cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); |
| 239 cur_loc &= MAP_SIZE - 1; |
| 240 |
| 241 /* Implement probabilistic instrumentation by looking at scrambled block |
| 242 address. This keeps the instrumented locations stable across runs. */ |
| 243 |
| 244 if (cur_loc >= afl_inst_rms) return; |
| 245 |
| 246 afl_area_ptr[cur_loc ^ prev_loc]++; |
| 247 prev_loc = cur_loc >> 1; |
| 248 |
| 249 } |
| 250 |
| 251 |
| 252 /* This code is invoked whenever QEMU decides that it doesn't have a |
| 253 translation of a particular block and needs to compute it. When this happens, |
| 254 we tell the parent to mirror the operation, so that the next fork() has a |
| 255 cached copy. */ |
| 256 |
| 257 static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) { |
| 258 |
| 259 struct afl_tsl t; |
| 260 |
| 261 if (!afl_fork_child) return; |
| 262 |
| 263 t.pc = pc; |
| 264 t.cs_base = cb; |
| 265 t.flags = flags; |
| 266 |
| 267 if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) |
| 268 return; |
| 269 |
| 270 } |
| 271 |
| 272 |
| 273 /* This is the other side of the same channel. Since timeouts are handled by |
| 274 afl-fuzz simply killing the child, we can just wait until the pipe breaks. */ |
| 275 |
| 276 static void afl_wait_tsl(CPUArchState *env, int fd) { |
| 277 |
| 278 struct afl_tsl t; |
| 279 |
| 280 while (1) { |
| 281 |
| 282 /* Broken pipe means it's time to return to the fork server routine. */ |
| 283 |
| 284 if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) |
| 285 break; |
| 286 |
| 287 tb_find_slow(env, t.pc, t.cs_base, t.flags); |
| 288 |
| 289 } |
| 290 |
| 291 close(fd); |
| 292 |
| 293 } |
| 294 |
OLD | NEW |