blob: 18c699d58f76f5b687fb10e1d3f8b1ae8c6b1c2f [file] [log] [blame]
robert.swiecki3bb518c2010-10-14 00:48:24 +00001/*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00002 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00003 * honggfuzz - architecture dependent code (LINUX/PTRACE)
4 * -----------------------------------------
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00005 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00006 * Author: Robert Swiecki <swiecki@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00007 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00008 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00009 *
10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
11 * not use this file except in compliance with the License. You may obtain
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000012 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000013 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000014 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000015 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000016 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
19 * implied. See the License for the specific language governing
20 * permissions and limitations under the License.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000021 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000022 */
robert.swiecki3bb518c2010-10-14 00:48:24 +000023
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000024#include "common.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000025#include "ptrace.h"
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000026
robert.swiecki3bb518c2010-10-14 00:48:24 +000027#include <ctype.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000028#include <dirent.h>
29#include <elf.h>
robert.swiecki@gmail.com4c1ad432015-02-03 11:04:13 +000030#include <endian.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000031#include <errno.h>
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000032#include <fcntl.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000033#include <signal.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <inttypes.h>
38#include <sys/cdefs.h>
39#include <sys/personality.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000040#include <sys/ptrace.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000041#include <sys/prctl.h>
42#include <sys/resource.h>
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000043#include <sys/stat.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000044#include <sys/time.h>
45#include <sys/types.h>
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +000046#include <sys/uio.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000047#include <sys/user.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000048#include <sys/wait.h>
49#include <time.h>
50#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000051
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000052#include "files.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000053#include "linux/bfd.h"
54#include "linux/unwind.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000055#include "log.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000056#include "util.h"
57
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +000058/* *INDENT-OFF* */
robert.swiecki3bb518c2010-10-14 00:48:24 +000059struct {
60 bool important;
61 const char *descr;
robert.swiecki@gmail.comb16e1d92015-02-03 03:46:06 +000062} arch_sigs[NSIG] = {
63 [0 ... (NSIG - 1)].important = false,
64 [0 ... (NSIG - 1)].descr = "UNKNOWN",
65
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +000066 [SIGILL].important = true,
67 [SIGILL].descr = "SIGILL",
68 [SIGFPE].important = true,
69 [SIGFPE].descr = "SIGFPE",
70 [SIGSEGV].important = true,
71 [SIGSEGV].descr = "SIGSEGV",
72 [SIGBUS].important = true,
73 [SIGBUS].descr = "SIGBUS",
74 [SIGABRT].important = true,
75 [SIGABRT].descr = "SIGABRT"
76};
77/* *INDENT-ON* */
robert.swiecki3bb518c2010-10-14 00:48:24 +000078
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000079bool arch_ptraceEnable(honggfuzz_t * hfuzz)
robert.swiecki3bb518c2010-10-14 00:48:24 +000080{
robert.swiecki28cba5c2011-06-22 01:38:55 +000081 // We're fuzzing an external process, so just return true
82 if (hfuzz->pid) {
83 return true;
84 }
85
robert.swiecki3bb518c2010-10-14 00:48:24 +000086 if (ptrace(PT_TRACE_ME, 0, 0, 0) == -1) {
87 LOGMSG_P(l_FATAL, "Couldn't attach ptrace to pid %d", getpid());
88 return false;
89 }
robert.swiecki3bb518c2010-10-14 00:48:24 +000090 return true;
91}
92
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000093static size_t arch_getProcMem(pid_t pid, uint8_t * buf, size_t len, uint64_t pc)
robert.swiecki3bb518c2010-10-14 00:48:24 +000094{
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000095 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000096 * Let's try process_vm_readv first
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000097 */
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +000098 const struct iovec local_iov = {
99 .iov_base = buf,
100 .iov_len = len,
101 };
102 const struct iovec remote_iov = {
103 .iov_base = (void *)(uintptr_t) pc,
104 .iov_len = len,
105 };
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000106 if (process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) == (ssize_t) len) {
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000107 return len;
108 }
109
robert.swiecki3bb518c2010-10-14 00:48:24 +0000110 /*
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000111 * Ok, let's do it via ptrace() then.
robert.swiecki3bb518c2010-10-14 00:48:24 +0000112 * len must be aligned to the sizeof(long)
113 */
114 int cnt = len / sizeof(long);
115 size_t memsz = 0;
116
117 for (int x = 0; x < cnt; x++) {
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000118 uint8_t *addr = (uint8_t *) (uintptr_t) pc + (int)(x * sizeof(long));
robert.swiecki3bb518c2010-10-14 00:48:24 +0000119 long ret = ptrace(PT_READ_D, pid, addr, NULL);
120
121 if (errno != 0) {
122 LOGMSG_P(l_WARN, "Couldn't PT_READ_D on pid %d, addr: %p", pid, addr);
123 break;
124 }
125
126 memsz += sizeof(long);
127 memcpy(&buf[x * sizeof(long)], &ret, sizeof(long));
128 }
129 return memsz;
130}
131
robert.swiecki@gmail.com26eee242015-02-16 12:21:36 +0000132static bool arch_getPC(pid_t pid, uint64_t * pc)
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000133{
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000134 char buf[1024];
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000135 struct iovec pt_iov = {
136 .iov_base = buf,
137 .iov_len = sizeof(buf),
138 };
robert.swiecki@gmail.com8a7d6982015-02-01 15:59:45 +0000139 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000140 LOGMSG_P(l_WARN, "ptrace(PTRACE_GETREGSET) failed");
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000141 return false;
142 }
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000143#if defined(__i386__) || defined(__x86_64__)
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000144 struct user_regs_struct_32 {
145 uint32_t ebx;
146 uint32_t ecx;
147 uint32_t edx;
148 uint32_t esi;
149 uint32_t edi;
150 uint32_t ebp;
151 uint32_t eax;
152 uint16_t ds, __ds;
153 uint16_t es, __es;
154 uint16_t fs, __fs;
155 uint16_t gs, __gs;
156 uint32_t orig_eax;
157 uint32_t eip;
158 uint16_t cs, __cs;
159 uint32_t eflags;
160 uint32_t esp;
161 uint16_t ss, __ss;
162 };
163
164 struct user_regs_struct_64 {
165 uint64_t r15;
166 uint64_t r14;
167 uint64_t r13;
168 uint64_t r12;
169 uint64_t bp;
170 uint64_t bx;
171 uint64_t r11;
172 uint64_t r10;
173 uint64_t r9;
174 uint64_t r8;
175 uint64_t ax;
176 uint64_t cx;
177 uint64_t dx;
178 uint64_t si;
179 uint64_t di;
180 uint64_t orig_ax;
181 uint64_t ip;
182 uint64_t cs;
183 uint64_t flags;
184 uint64_t sp;
185 uint64_t ss;
186 uint64_t fs_base;
187 uint64_t gs_base;
188 uint64_t ds;
189 uint64_t es;
190 uint64_t fs;
191 uint64_t gs;
192 };
193
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000194 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000195 * 32-bit
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000196 */
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000197 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
198 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000199 *pc = r32->eip;
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000200 return true;
201 }
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000202 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000203 * 64-bit
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000204 */
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000205 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
206 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000207 *pc = r64->ip;
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000208 return true;
209 }
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000210 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000211 return false;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000212#endif /* defined(__i386__) ||
213 * defined(__x86_64__) */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000214#if defined(__arm__)
215 struct user_regs_struct_32 {
216 uint32_t uregs[18];
217 };
218 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
219 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000220#ifndef ARM_pc
221#define ARM_pc 15
222#endif /* ARM_pc */
223 *pc = r32->uregs[ARM_pc];
224 return true;
225 }
226 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
227 return false;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000228#endif /* defined(__arm__) */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000229#if defined(__aarch64__)
230 struct user_regs_struct_64 {
231 uint64_t regs[31];
232 uint64_t sp;
233 uint64_t pc;
234 uint64_t pstate;
235 };
236 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
237 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000238 *pc = r64->pc;
239 return true;
240 }
241 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
242 return false;
243#endif /* defined(__aarch64__) */
244#if defined(__powerpc64__) || defined(__powerpc__)
245 struct user_regs_struct_32 {
246 uint32_t gpr[32];
247 uint32_t nip;
248 uint32_t msr;
249 uint32_t orig_gpr3;
250 uint32_t ctr;
251 uint32_t link;
252 uint32_t xer;
253 uint32_t ccr;
254 uint32_t mq;
255 uint32_t trap;
256 uint32_t dar;
257 uint32_t dsisr;
258 uint32_t result;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000259 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000260 * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
261 * with some zeros
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000262 */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000263 uint32_t zero0;
264 uint32_t zero1;
265 uint32_t zero2;
266 uint32_t zero3;
267 };
268 struct user_regs_struct_64 {
269 uint64_t gpr[32];
270 uint64_t nip;
271 uint64_t msr;
272 uint64_t orig_gpr3;
273 uint64_t ctr;
274 uint64_t link;
275 uint64_t xer;
276 uint64_t ccr;
277 uint64_t softe;
278 uint64_t trap;
279 uint64_t dar;
280 uint64_t dsisr;
281 uint64_t result;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000282 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000283 * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
284 * with some zeros
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000285 */
robert.swiecki@gmail.com7e818512015-02-02 01:59:47 +0000286 uint64_t zero0;
287 uint64_t zero1;
288 uint64_t zero2;
289 uint64_t zero3;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000290 };
291 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
292 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000293 *pc = r32->nip;
294 return true;
295 }
296 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
297 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000298 *pc = r64->nip;
299 return true;
300 }
301 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
302 return false;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000303#endif /* defined(__powerpc64__) ||
304 * defined(__powerpc__) */
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000305 LOGMSG(l_DEBUG, "Unknown/unsupported CPU architecture");
306 return false;
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000307}
308
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000309static void arch_getInstrStr(pid_t pid, uint64_t * pc, char *instr)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000310{
311 /*
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000312 * We need a value aligned to 8
robert.swiecki3bb518c2010-10-14 00:48:24 +0000313 * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
314 */
315 uint8_t buf[16];
316 size_t memsz;
317
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000318 snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000319
robert.swiecki@gmail.com26eee242015-02-16 12:21:36 +0000320 if (!arch_getPC(pid, pc)) {
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000321 LOGMSG(l_WARN, "Current architecture not supported for disassembly");
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000322 return;
323 }
324
325 if ((memsz = arch_getProcMem(pid, buf, sizeof(buf), *pc)) == 0) {
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000326 snprintf(instr, _HF_INSTR_SZ, "%s", "[NOT_MMAPED]");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000327 return;
328 }
329
robert.swiecki@gmail.com26eee242015-02-16 12:21:36 +0000330 arch_bfdDisasm(pid, buf, memsz, instr);
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000331
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000332 for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000333 if (instr[x] == '/' || instr[x] == '\\' || isspace(instr[x])
334 || !isprint(instr[x])) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000335 instr[x] = '_';
336 }
337 }
robert.swiecki@gmail.com26eee242015-02-16 12:21:36 +0000338
339 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000340}
341
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000342static void
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000343arch_ptraceGenerateReport(pid_t pid, fuzzer_t * fuzzer, funcs_t * funcs,
344 size_t funcCnt, siginfo_t * si, const char *instr)
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000345{
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000346 fuzzer->report[0] = '\0';
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000347 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "ORIG_FNAME: %s\n",
348 fuzzer->origFileName);
349 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "FUZZ_FNAME: %s\n", fuzzer->fileName);
350 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "PID: %d\n", pid);
351 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "SIGNAL: %s (%d)\n",
352 arch_sigs[si->si_signo].descr, si->si_signo);
353 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "FAULT ADDRESS: %p\n", si->si_addr);
354 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "INSTRUCTION: %s\n", instr);
355 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "STACK:\n");
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000356 for (size_t i = 0; i < funcCnt; i++) {
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000357 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <0x%016" PRIx64 "> [%s():%d]\n",
358 (uint64_t) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000359 }
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000360
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000361 return;
362}
363
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000364static void arch_ptraceSaveData(honggfuzz_t * hfuzz, pid_t pid, fuzzer_t * fuzzer)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000365{
robert.swiecki@gmail.com8118eb62015-02-20 12:01:41 +0000366 uint64_t pc = 0ULL;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000367
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000368 char instr[_HF_INSTR_SZ] = "\x00";
robert.swiecki3bb518c2010-10-14 00:48:24 +0000369 siginfo_t si;
370
371 if (ptrace(PT_GETSIGINFO, pid, 0, &si) == -1) {
372 LOGMSG_P(l_WARN, "Couldn't get siginfo for pid %d", pid);
373 return;
374 }
375
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000376 arch_getInstrStr(pid, &pc, instr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000377
378 LOGMSG(l_DEBUG,
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000379 "Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %"
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000380 PRIx64 ", instr: '%s'", pid, si.si_signo, si.si_errno, si.si_code, si.si_addr, pc,
381 instr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000382
robert.swiecki3bb518c2010-10-14 00:48:24 +0000383 if (si.si_addr < hfuzz->ignoreAddr) {
384 LOGMSG(l_INFO,
385 "'%s' is interesting (%s), but the si.si_addr is %p (below %p), skipping",
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000386 fuzzer->fileName, arch_sigs[si.si_signo].descr, si.si_addr, hfuzz->ignoreAddr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000387 return;
388 }
389
390 char newname[PATH_MAX];
391 if (hfuzz->saveUnique) {
392 snprintf(newname, sizeof(newname),
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000393 "%s.PC.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%s",
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000394 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
395 instr, fuzzer->origFileName, hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000396 } else {
397 char localtmstr[PATH_MAX];
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000398 util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr));
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000399 snprintf(newname, sizeof(newname),
400 "%s.PC.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s.%s",
401 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
402 instr, localtmstr, pid, fuzzer->origFileName, hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000403 }
404
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000405 if (link(fuzzer->fileName, newname) == 0) {
406 LOGMSG(l_INFO, "Ok, that's interesting, saved '%s' as '%s'", fuzzer->fileName, newname);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000407 } else {
408 if (errno == EEXIST) {
409 LOGMSG(l_INFO, "It seems that '%s' already exists, skipping", newname);
410 } else {
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000411 LOGMSG_P(l_ERROR, "Couldn't link '%s' to '%s'", fuzzer->fileName, newname);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000412 }
413 }
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +0000414
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000415 funcs_t funcs[_HF_MAX_FUNCS] = {
416 [0 ... (_HF_MAX_FUNCS - 1)].pc = NULL,
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000417 [0 ... (_HF_MAX_FUNCS - 1)].line = 0,
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000418 [0 ... (_HF_MAX_FUNCS - 1)].func = {'\0'}
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000419 ,
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000420 };
421
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000422 size_t funcCnt = arch_unwindStack(pid, funcs);
423 arch_bfdResolveSyms(pid, funcs, funcCnt);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000424
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000425 arch_ptraceGenerateReport(pid, fuzzer, funcs, funcCnt, &si, instr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000426}
427
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000428void arch_ptraceAnalyze(honggfuzz_t * hfuzz, int status, pid_t pid, fuzzer_t * fuzzer)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000429{
430 /*
431 * If it's an uninteresting signal (even SIGTRAP), let it run and relay the
432 * signal (if not SIGTRAP)
433 */
434 if (WIFSTOPPED(status) && !arch_sigs[WSTOPSIG(status)].important) {
435 int sig = WSTOPSIG(status) == SIGTRAP ? 0 : WSTOPSIG(status);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000436 ptrace(PT_CONTINUE, pid, 0, sig);
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000437 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000438 }
439
440 /*
441 * If it's an interesting signal, save the testcase, and detach
442 * the tracer (relay the signal as well)
443 */
444 if (WIFSTOPPED(status) && arch_sigs[WSTOPSIG(status)].important) {
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000445 arch_ptraceSaveData(hfuzz, pid, fuzzer);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000446 ptrace(PT_CONTINUE, pid, 0, WSTOPSIG(status));
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000447 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000448 }
449
450 /*
451 * Resumed by delivery of SIGCONT
452 */
453 if (WIFCONTINUED(status)) {
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000454 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000455 }
456
457 /*
robert.swiecki@gmail.com124ba812011-06-22 15:51:56 +0000458 * Process exited
robert.swiecki3bb518c2010-10-14 00:48:24 +0000459 */
robert.swiecki@gmail.com124ba812011-06-22 15:51:56 +0000460 if (WIFEXITED(status) || WIFSIGNALED(status)) {
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000461 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000462 }
463
464 abort(); /* NOTREACHED */
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000465 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000466}
467
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000468static bool arch_listThreads(int tasks[], size_t thrSz, int pid)
469{
470 size_t count = 0;
471 char path[512];
472 snprintf(path, sizeof(path), "/proc/%d/task", pid);
473 DIR *dir = opendir(path);
474 if (!dir) {
475 LOGMSG_P(l_ERROR, "Couldn't open dir '%s'", path);
476 return false;
477 }
478
479 for (;;) {
480 struct dirent de, *res;
481 if (readdir_r(dir, &de, &res) > 0) {
482 LOGMSG_P(l_ERROR, "Couldn't read contents of '%s'", path);
483 closedir(dir);
484 return false;
485 }
486
487 if (res == NULL) {
488 break;
489 }
490
491 pid_t pid = (pid_t) strtol(res->d_name, (char **)NULL, 10);
492 if (pid == 0) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000493 LOGMSG(l_DEBUG, "The following dir entry couldn't be converted to pid_t '%s'",
494 res->d_name);
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000495 continue;
496 }
497
498 tasks[count++] = pid;
499 LOGMSG(l_DEBUG, "Added pid '%d' from '%s/%s'", pid, path, res->d_name);
500
501 if (count >= thrSz) {
502 break;
503 }
504 }
505 closedir(dir);
506 LOGMSG_P(l_DEBUG, "Total number of threads in pid '%d': '%d'", pid, count);
507 tasks[count + 1] = 0;
508 if (count < 1) {
509 return false;
510 }
511 return true;
512}
513
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000514bool arch_ptracePrepare(honggfuzz_t * hfuzz)
robert.swiecki28cba5c2011-06-22 01:38:55 +0000515{
516 if (!hfuzz->pid) {
517 return true;
518 }
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000519#define MAX_THREAD_IN_TASK 4096
520 int tasks[MAX_THREAD_IN_TASK + 1];
521 tasks[MAX_THREAD_IN_TASK] = 0;
522 if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, hfuzz->pid)) {
523 LOGMSG(l_ERROR, "Couldn't read thread list for pid '%d'", hfuzz->pid);
robert.swiecki28cba5c2011-06-22 01:38:55 +0000524 return false;
525 }
526
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000527 for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
528 if (ptrace(PT_ATTACH, tasks[i], NULL, NULL) == -1) {
robert.swiecki@gmail.com3b4256d2015-02-13 17:22:41 +0000529 LOGMSG_P(l_ERROR, "Couldn't ptrace(PTRACE_ATTACH) to pid: %d", tasks[i]);
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000530 return false;
531 }
robert.swiecki28cba5c2011-06-22 01:38:55 +0000532
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000533 int status;
534 while (waitpid(tasks[i], &status, WUNTRACED | __WALL) != tasks[i]) ;
535
robert.swiecki@gmail.com3b4256d2015-02-13 17:22:41 +0000536 if (ptrace(PTRACE_SETOPTIONS, tasks[i], NULL,
537 PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK) == -1) {
538 LOGMSG_P(l_ERROR, "Couldn't ptrace(PTRACE_SETOPTIONS) pid: %d", tasks[i]);
539 ptrace(PT_DETACH, tasks[i], 0, SIGCONT);
540 return false;
541 }
542
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000543 if (ptrace(PT_CONTINUE, tasks[i], NULL, NULL) == -1) {
robert.swiecki@gmail.com3b4256d2015-02-13 17:22:41 +0000544 LOGMSG_P(l_ERROR, "Couldn't ptrace(PTRACE_CONTINUE) pid: %d", tasks[i]);
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000545 ptrace(PT_DETACH, tasks[i], 0, SIGCONT);
546 return false;
547 }
548
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000549 LOGMSG(l_INFO, "Successfully attached to pid/tid: %d", tasks[i]);
robert.swiecki28cba5c2011-06-22 01:38:55 +0000550 }
robert.swiecki28cba5c2011-06-22 01:38:55 +0000551 return true;
552}