• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * honggfuzz - architecture dependent code (LINUX/PTRACE)
4  * -----------------------------------------
5  *
6  * Author: Robert Swiecki <swiecki@google.com>
7  *
8  * Copyright 2010-2015 by Google Inc. All Rights Reserved.
9  *
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
12  * a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * 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.
21  *
22  */
23 
24 #include "linux/trace.h"
25 
26 #include <ctype.h>
27 #include <dirent.h>
28 #include <elf.h>
29 #include <endian.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <inttypes.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/cdefs.h>
38 #include <sys/personality.h>
39 #include <sys/ptrace.h>
40 #include <sys/resource.h>
41 #include <sys/stat.h>
42 #include <sys/syscall.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <sys/uio.h>
46 #include <sys/user.h>
47 #include <sys/wait.h>
48 #include <time.h>
49 #include <unistd.h>
50 
51 #include "libcommon/common.h"
52 #include "libcommon/files.h"
53 #include "libcommon/log.h"
54 #include "libcommon/util.h"
55 #include "linux/bfd.h"
56 #include "linux/unwind.h"
57 #include "sancov.h"
58 #include "sanitizers.h"
59 #include "subproc.h"
60 
61 #if defined(__ANDROID__)
62 #include "capstone.h"
63 #endif
64 
65 #if defined(__i386__) || defined(__arm__) || defined(__powerpc__)
66 #define REG_TYPE uint32_t
67 #define REG_PM PRIx32
68 #define REG_PD "0x%08"
69 #elif defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \
70     defined(__mips__) || defined(__mips64__)
71 #define REG_TYPE uint64_t
72 #define REG_PM PRIx64
73 #define REG_PD "0x%016"
74 #endif
75 
76 /*
77  * Size in characters required to store a string representation of a
78  * register value (0xdeadbeef style))
79  */
80 #define REGSIZEINCHAR (2 * sizeof(REG_TYPE) + 3)
81 
82 #if defined(__i386__) || defined(__x86_64__)
83 #define MAX_INSTR_SZ 16
84 #elif defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
85 #define MAX_INSTR_SZ 4
86 #elif defined(__aarch64__)
87 #define MAX_INSTR_SZ 8
88 #elif defined(__mips__) || defined(__mips64__)
89 #define MAX_INSTR_SZ 8
90 #endif
91 
92 #if defined(__i386__) || defined(__x86_64__)
93 struct user_regs_struct_32 {
94     uint32_t ebx;
95     uint32_t ecx;
96     uint32_t edx;
97     uint32_t esi;
98     uint32_t edi;
99     uint32_t ebp;
100     uint32_t eax;
101     uint16_t ds, __ds;
102     uint16_t es, __es;
103     uint16_t fs, __fs;
104     uint16_t gs, __gs;
105     uint32_t orig_eax;
106     uint32_t eip;
107     uint16_t cs, __cs;
108     uint32_t eflags;
109     uint32_t esp;
110     uint16_t ss, __ss;
111 };
112 
113 struct user_regs_struct_64 {
114     uint64_t r15;
115     uint64_t r14;
116     uint64_t r13;
117     uint64_t r12;
118     uint64_t bp;
119     uint64_t bx;
120     uint64_t r11;
121     uint64_t r10;
122     uint64_t r9;
123     uint64_t r8;
124     uint64_t ax;
125     uint64_t cx;
126     uint64_t dx;
127     uint64_t si;
128     uint64_t di;
129     uint64_t orig_ax;
130     uint64_t ip;
131     uint64_t cs;
132     uint64_t flags;
133     uint64_t sp;
134     uint64_t ss;
135     uint64_t fs_base;
136     uint64_t gs_base;
137     uint64_t ds;
138     uint64_t es;
139     uint64_t fs;
140     uint64_t gs;
141 };
142 #define HEADERS_STRUCT struct user_regs_struct_64
143 #endif /* defined(__i386__) || defined(__x86_64__) */
144 
145 #if defined(__arm__) || defined(__aarch64__)
146 #ifndef ARM_pc
147 #ifdef __ANDROID__ /* Building with NDK headers */
148 #define ARM_pc uregs[15]
149 #else /* Building with glibc headers */
150 #define ARM_pc 15
151 #endif
152 #endif /* ARM_pc */
153 #ifndef ARM_cpsr
154 #ifdef __ANDROID__ /* Building with NDK headers */
155 #define ARM_cpsr uregs[16]
156 #else /* Building with glibc headers */
157 #define ARM_cpsr 16
158 #endif
159 #endif /* ARM_cpsr */
160 struct user_regs_struct_32 {
161     uint32_t uregs[18];
162 };
163 
164 struct user_regs_struct_64 {
165     uint64_t regs[31];
166     uint64_t sp;
167     uint64_t pc;
168     uint64_t pstate;
169 };
170 #define HEADERS_STRUCT struct user_regs_struct_64
171 #endif /* defined(__arm__) || defined(__aarch64__) */
172 
173 #if defined(__powerpc64__) || defined(__powerpc__)
174 #define HEADERS_STRUCT struct pt_regs
175 struct user_regs_struct_32 {
176     uint32_t gpr[32];
177     uint32_t nip;
178     uint32_t msr;
179     uint32_t orig_gpr3;
180     uint32_t ctr;
181     uint32_t link;
182     uint32_t xer;
183     uint32_t ccr;
184     uint32_t mq;
185     uint32_t trap;
186     uint32_t dar;
187     uint32_t dsisr;
188     uint32_t result;
189     /*
190      * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
191      * with some zeros
192      */
193     uint32_t zero0;
194     uint32_t zero1;
195     uint32_t zero2;
196     uint32_t zero3;
197 };
198 struct user_regs_struct_64 {
199     uint64_t gpr[32];
200     uint64_t nip;
201     uint64_t msr;
202     uint64_t orig_gpr3;
203     uint64_t ctr;
204     uint64_t link;
205     uint64_t xer;
206     uint64_t ccr;
207     uint64_t softe;
208     uint64_t trap;
209     uint64_t dar;
210     uint64_t dsisr;
211     uint64_t result;
212     /*
213      * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
214      * with some zeros
215      */
216     uint64_t zero0;
217     uint64_t zero1;
218     uint64_t zero2;
219     uint64_t zero3;
220 };
221 #endif /* defined(__powerpc64__) || defined(__powerpc__) */
222 
223 #if defined(__mips__) || defined(__mips64__)
224 struct user_regs_struct {
225     uint64_t regs[32];
226 
227     uint64_t lo;
228     uint64_t hi;
229     uint64_t cp0_epc;
230     uint64_t cp0_badvaddr;
231     uint64_t cp0_status;
232     uint64_t cp0_cause;
233 };
234 #define HEADERS_STRUCT struct user_regs_struct
235 #endif /* defined(__mips__) || defined(__mips64__) */
236 
237 #if defined(__ANDROID__)
238 /*
239  * Some Android ABIs don't implement PTRACE_GETREGS (e.g. aarch64)
240  */
241 #if defined(PTRACE_GETREGS)
242 #define PTRACE_GETREGS_AVAILABLE 1
243 #else
244 #define PTRACE_GETREGS_AVAILABLE 0
245 #endif /* defined(PTRACE_GETREGS) */
246 #endif /* defined(__ANDROID__) */
247 
248 static struct {
249     const char* descr;
250     bool important;
251 } arch_sigs[_NSIG + 1] = {
252     [0 ...(_NSIG)].important = false,
253     [0 ...(_NSIG)].descr = "UNKNOWN",
254 
255     [SIGTRAP].important = false,
256     [SIGTRAP].descr = "SIGTRAP",
257 
258     [SIGILL].important = true,
259     [SIGILL].descr = "SIGILL",
260 
261     [SIGFPE].important = true,
262     [SIGFPE].descr = "SIGFPE",
263 
264     [SIGSEGV].important = true,
265     [SIGSEGV].descr = "SIGSEGV",
266 
267     [SIGBUS].important = true,
268     [SIGBUS].descr = "SIGBUS",
269 
270     /* Is affected from monitorSIGABRT flag */
271     [SIGABRT].important = false,
272     [SIGABRT].descr = "SIGABRT",
273 
274     /* Is affected from tmoutVTALRM flag */
275     [SIGVTALRM].important = false,
276     [SIGVTALRM].descr = "SIGVTALRM-TMOUT",
277 
278     /* seccomp-bpf kill */
279     [SIGSYS].important = true,
280     [SIGSYS].descr = "SIGSYS",
281 };
282 
283 #ifndef SI_FROMUSER
284 #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
285 #endif /* SI_FROMUSER */
286 
287 extern const char* sys_sigabbrev[];
288 
289 static __thread char arch_signame[32];
arch_sigName(int signo)290 static const char* arch_sigName(int signo) {
291     if (signo < 0 || signo > _NSIG) {
292         snprintf(arch_signame, sizeof(arch_signame), "UNKNOWN-%d", signo);
293         return arch_signame;
294     }
295     if (signo > __SIGRTMIN) {
296         snprintf(arch_signame, sizeof(arch_signame), "SIG%d-RTMIN+%d", signo, signo - __SIGRTMIN);
297         return arch_signame;
298     }
299 #ifdef __ANDROID__
300     return arch_sigs[signo].descr;
301 #else
302     if (sys_sigabbrev[signo] == NULL) {
303         snprintf(arch_signame, sizeof(arch_signame), "SIG%d", signo);
304     } else {
305         snprintf(arch_signame, sizeof(arch_signame), "SIG%s", sys_sigabbrev[signo]);
306     }
307     return arch_signame;
308 #endif /* __ANDROID__ */
309 }
310 
arch_getProcMem(pid_t pid,uint8_t * buf,size_t len,REG_TYPE pc)311 static size_t arch_getProcMem(pid_t pid, uint8_t* buf, size_t len, REG_TYPE pc) {
312     /*
313      * Let's try process_vm_readv first
314      */
315     const struct iovec local_iov = {
316         .iov_base = buf,
317         .iov_len = len,
318     };
319     const struct iovec remote_iov = {
320         .iov_base = (void*)(uintptr_t)pc,
321         .iov_len = len,
322     };
323     if (process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) == (ssize_t)len) {
324         return len;
325     }
326     // Debug if failed since it shouldn't happen very often
327     PLOG_D("process_vm_readv() failed");
328 
329     /*
330      * Ok, let's do it via ptrace() then.
331      * len must be aligned to the sizeof(long)
332      */
333     int cnt = len / sizeof(long);
334     size_t memsz = 0;
335 
336     for (int x = 0; x < cnt; x++) {
337         uint8_t* addr = (uint8_t*)(uintptr_t)pc + (int)(x * sizeof(long));
338         long ret = ptrace(PTRACE_PEEKDATA, pid, addr, NULL);
339 
340         if (errno != 0) {
341             PLOG_W("Couldn't PT_READ_D on pid %d, addr: %p", pid, addr);
342             break;
343         }
344 
345         memsz += sizeof(long);
346         memcpy(&buf[x * sizeof(long)], &ret, sizeof(long));
347     }
348     return memsz;
349 }
350 
arch_getPC(pid_t pid,REG_TYPE * pc,REG_TYPE * status_reg UNUSED)351 static size_t arch_getPC(pid_t pid, REG_TYPE* pc, REG_TYPE* status_reg UNUSED) {
352 /*
353  * Some old ARM android kernels are failing with PTRACE_GETREGS to extract
354  * the correct register values if struct size is bigger than expected. As such the
355  * 32/64-bit multiplexing trick is not working for them in case PTRACE_GETREGSET
356  * fails or is not implemented. To cover such cases we explicitly define
357  * the struct size to 32bit version for arm CPU.
358  */
359 #if defined(__arm__)
360     struct user_regs_struct_32 regs;
361 #else
362     HEADERS_STRUCT regs;
363 #endif
364     struct iovec pt_iov = {
365         .iov_base = &regs,
366         .iov_len = sizeof(regs),
367     };
368 
369     if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
370         PLOG_D("ptrace(PTRACE_GETREGSET) failed");
371 
372 // If PTRACE_GETREGSET fails, try PTRACE_GETREGS if available
373 #if PTRACE_GETREGS_AVAILABLE
374         if (ptrace(PTRACE_GETREGS, pid, 0, &regs)) {
375             PLOG_D("ptrace(PTRACE_GETREGS) failed");
376             LOG_W("ptrace PTRACE_GETREGSET & PTRACE_GETREGS failed to extract target registers");
377             return 0;
378         }
379 #else
380         return 0;
381 #endif
382     }
383 #if defined(__i386__) || defined(__x86_64__)
384     /*
385      * 32-bit
386      */
387     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
388         struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)&regs;
389         *pc = r32->eip;
390         *status_reg = r32->eflags;
391         return pt_iov.iov_len;
392     }
393 
394     /*
395      * 64-bit
396      */
397     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
398         struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)&regs;
399         *pc = r64->ip;
400         *status_reg = r64->flags;
401         return pt_iov.iov_len;
402     }
403     LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len);
404     return 0;
405 #endif /* defined(__i386__) || defined(__x86_64__) */
406 
407 #if defined(__arm__) || defined(__aarch64__)
408     /*
409      * 32-bit
410      */
411     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
412         struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)&regs;
413 #ifdef __ANDROID__
414         *pc = r32->ARM_pc;
415         *status_reg = r32->ARM_cpsr;
416 #else
417         *pc = r32->uregs[ARM_pc];
418         *status_reg = r32->uregs[ARM_cpsr];
419 #endif
420         return pt_iov.iov_len;
421     }
422 
423     /*
424      * 64-bit
425      */
426     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
427         struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)&regs;
428         *pc = r64->pc;
429         *status_reg = r64->pstate;
430         return pt_iov.iov_len;
431     }
432     LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len);
433     return 0;
434 #endif /* defined(__arm__) || defined(__aarch64__) */
435 
436 #if defined(__powerpc64__) || defined(__powerpc__)
437     /*
438      * 32-bit
439      */
440     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
441         struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)&regs;
442         *pc = r32->nip;
443         return pt_iov.iov_len;
444     }
445 
446     /*
447      * 64-bit
448      */
449     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
450         struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)&regs;
451         *pc = r64->nip;
452         return pt_iov.iov_len;
453     }
454 
455     LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len);
456     return 0;
457 #endif /* defined(__powerpc64__) || defined(__powerpc__) */
458 
459 #if defined(__mips__) || defined(__mips64__)
460     *pc = regs.cp0_epc;
461     return pt_iov.iov_len;
462 #endif /* defined(__mips__) || defined(__mips64__) */
463 
464     LOG_D("Unknown/unsupported CPU architecture");
465     return 0;
466 }
467 
arch_getInstrStr(pid_t pid,REG_TYPE * pc,char * instr)468 static void arch_getInstrStr(pid_t pid, REG_TYPE* pc, char* instr) {
469     /*
470      * We need a value aligned to 8
471      * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
472      */
473     uint8_t buf[MAX_INSTR_SZ];
474     size_t memsz;
475     REG_TYPE status_reg = 0;
476 
477     snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");
478 
479     size_t pcRegSz = arch_getPC(pid, pc, &status_reg);
480     if (!pcRegSz) {
481         LOG_W("Current architecture not supported for disassembly");
482         return;
483     }
484 
485     if ((memsz = arch_getProcMem(pid, buf, sizeof(buf), *pc)) == 0) {
486         snprintf(instr, _HF_INSTR_SZ, "%s", "[NOT_MMAPED]");
487         return;
488     }
489 #if !defined(__ANDROID__)
490     arch_bfdDisasm(pid, buf, memsz, instr);
491 #else
492     cs_arch arch;
493     cs_mode mode;
494 #if defined(__arm__) || defined(__aarch64__)
495     arch = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_ARCH_ARM64 : CS_ARCH_ARM;
496     if (arch == CS_ARCH_ARM) {
497         mode = (status_reg & 0x20) ? CS_MODE_THUMB : CS_MODE_ARM;
498     } else {
499         mode = CS_MODE_ARM;
500     }
501 #elif defined(__i386__) || defined(__x86_64__)
502     arch = CS_ARCH_X86;
503     mode = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_MODE_64 : CS_MODE_32;
504 #else
505     LOG_E("Unknown/Unsupported Android CPU architecture");
506 #endif
507 
508     csh handle;
509     cs_err err = cs_open(arch, mode, &handle);
510     if (err != CS_ERR_OK) {
511         LOG_W("Capstone initialization failed: '%s'", cs_strerror(err));
512         return;
513     }
514 
515     cs_insn* insn;
516     size_t count = cs_disasm(handle, buf, sizeof(buf), *pc, 0, &insn);
517 
518     if (count < 1) {
519         LOG_W("Couldn't disassemble the assembler instructions' stream: '%s'",
520             cs_strerror(cs_errno(handle)));
521         cs_close(&handle);
522         return;
523     }
524 
525     snprintf(instr, _HF_INSTR_SZ, "%s %s", insn[0].mnemonic, insn[0].op_str);
526     cs_free(insn, count);
527     cs_close(&handle);
528 #endif /* defined(__ANDROID__) */
529 
530     for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
531         if (instr[x] == '/' || instr[x] == '\\' || isspace(instr[x]) || !isprint(instr[x])) {
532             instr[x] = '_';
533         }
534     }
535 
536     return;
537 }
538 
arch_hashCallstack(run_t * run,funcs_t * funcs,size_t funcCnt,bool enableMasking)539 static void arch_hashCallstack(run_t* run, funcs_t* funcs, size_t funcCnt, bool enableMasking) {
540     uint64_t hash = 0;
541     for (size_t i = 0; i < funcCnt && i < run->global->linux.numMajorFrames; i++) {
542         /*
543          * Convert PC to char array to be compatible with hash function
544          */
545         char pcStr[REGSIZEINCHAR] = {0};
546         snprintf(pcStr, REGSIZEINCHAR, REG_PD REG_PM, (REG_TYPE)(long)funcs[i].pc);
547 
548         /*
549          * Hash the last three nibbles
550          */
551         hash ^= util_hash(&pcStr[strlen(pcStr) - 3], 3);
552     }
553 
554     /*
555      * If only one frame, hash is not safe to be used for uniqueness. We mask it
556      * here with a constant prefix, so analyzers can pick it up and create filenames
557      * accordingly. 'enableMasking' is controlling masking for cases where it should
558      * not be enabled (e.g. fuzzer worker is from verifier).
559      */
560     if (enableMasking && funcCnt == 1) {
561         hash |= _HF_SINGLE_FRAME_MASK;
562     }
563     run->backtrace = hash;
564 }
565 
arch_traceGenerateReport(pid_t pid,run_t * run,funcs_t * funcs,size_t funcCnt,siginfo_t * si,const char * instr)566 static void arch_traceGenerateReport(
567     pid_t pid, run_t* run, funcs_t* funcs, size_t funcCnt, siginfo_t* si, const char* instr) {
568     run->report[0] = '\0';
569     util_ssnprintf(run->report, sizeof(run->report), "ORIG_FNAME: %s\n", run->origFileName);
570     util_ssnprintf(run->report, sizeof(run->report), "FUZZ_FNAME: %s\n", run->crashFileName);
571     util_ssnprintf(run->report, sizeof(run->report), "PID: %d\n", pid);
572     util_ssnprintf(run->report, sizeof(run->report), "SIGNAL: %s (%d)\n",
573         arch_sigName(si->si_signo), si->si_signo);
574     util_ssnprintf(run->report, sizeof(run->report), "FAULT ADDRESS: %p\n",
575         SI_FROMUSER(si) ? NULL : si->si_addr);
576     util_ssnprintf(run->report, sizeof(run->report), "INSTRUCTION: %s\n", instr);
577     util_ssnprintf(run->report, sizeof(run->report), "STACK HASH: %016llx\n", run->backtrace);
578     util_ssnprintf(run->report, sizeof(run->report), "STACK:\n");
579     for (size_t i = 0; i < funcCnt; i++) {
580 #ifdef __HF_USE_CAPSTONE__
581         util_ssnprintf(
582             run->report, sizeof(run->report), " <" REG_PD REG_PM "> ", (REG_TYPE)(long)funcs[i].pc);
583         if (funcs[i].func[0] != '\0')
584             util_ssnprintf(run->report, sizeof(run->report), "[%s() + 0x%x at %s]\n", funcs[i].func,
585                 funcs[i].line, funcs[i].mapName);
586         else
587             util_ssnprintf(run->report, sizeof(run->report), "[]\n");
588 #else
589         util_ssnprintf(run->report, sizeof(run->report), " <" REG_PD REG_PM "> [%s():%u at %s]\n",
590             (REG_TYPE)(long)funcs[i].pc, funcs[i].func, funcs[i].line, funcs[i].mapName);
591 #endif
592     }
593 
594 // libunwind is not working for 32bit targets in 64bit systems
595 #if defined(__aarch64__)
596     if (funcCnt == 0) {
597         util_ssnprintf(run->report, sizeof(run->report),
598             " !ERROR: If 32bit fuzz target"
599             " in aarch64 system, try ARM 32bit build\n");
600     }
601 #endif
602 
603     return;
604 }
605 
arch_traceAnalyzeData(run_t * run,pid_t pid)606 static void arch_traceAnalyzeData(run_t* run, pid_t pid) {
607     REG_TYPE pc = 0, status_reg = 0;
608     size_t pcRegSz = arch_getPC(pid, &pc, &status_reg);
609     if (!pcRegSz) {
610         LOG_W("ptrace arch_getPC failed");
611         return;
612     }
613 
614     /*
615      * Unwind and resolve symbols
616      */
617     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
618     defer { free(funcs); };
619     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
620 
621 #if !defined(__ANDROID__)
622     size_t funcCnt = arch_unwindStack(pid, funcs);
623     arch_bfdResolveSyms(pid, funcs, funcCnt);
624 #else
625     size_t funcCnt = arch_unwindStack(pid, funcs);
626 #endif
627 
628     /*
629      * If unwinder failed (zero frames), use PC from ptrace GETREGS if not zero.
630      * If PC reg zero return and callers should handle zero hash case.
631      */
632     if (funcCnt == 0) {
633         if (pc) {
634             /* Manually update major frame PC & frames counter */
635             funcs[0].pc = (void*)(uintptr_t)pc;
636             funcCnt = 1;
637         } else {
638             return;
639         }
640     }
641 
642     /*
643      * Calculate backtrace callstack hash signature
644      */
645     arch_hashCallstack(run, funcs, funcCnt, false);
646 }
647 
arch_traceSaveData(run_t * run,pid_t pid)648 static void arch_traceSaveData(run_t* run, pid_t pid) {
649     REG_TYPE pc = 0;
650 
651     /* Local copy since flag is overridden for some crashes */
652     bool saveUnique = run->global->io.saveUnique;
653 
654     char instr[_HF_INSTR_SZ] = "\x00";
655     siginfo_t si;
656     bzero(&si, sizeof(si));
657 
658     if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == -1) {
659         PLOG_W("Couldn't get siginfo for pid %d", pid);
660     }
661 
662     arch_getInstrStr(pid, &pc, instr);
663 
664     LOG_D("Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %" REG_PM ", instr: '%s'", pid,
665         si.si_signo, si.si_errno, si.si_code, si.si_addr, pc, instr);
666 
667     if (!SI_FROMUSER(&si) && pc && si.si_addr < run->global->linux.ignoreAddr) {
668         LOG_I("'%s' is interesting (%s), but the si.si_addr is %p (below %p), skipping",
669             run->fileName, arch_sigName(si.si_signo), si.si_addr, run->global->linux.ignoreAddr);
670         return;
671     }
672 
673     /*
674      * Unwind and resolve symbols
675      */
676     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
677     defer { free(funcs); };
678     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
679 
680 #if !defined(__ANDROID__)
681     size_t funcCnt = arch_unwindStack(pid, funcs);
682     arch_bfdResolveSyms(pid, funcs, funcCnt);
683 #else
684     size_t funcCnt = arch_unwindStack(pid, funcs);
685 #endif
686 
687     /*
688      * If unwinder failed (zero frames), use PC from ptrace GETREGS if not zero.
689      * If PC reg zero, temporarily disable uniqueness flag since callstack
690      * hash will be also zero, thus not safe for unique decisions.
691      */
692     if (funcCnt == 0) {
693         if (pc) {
694             /* Manually update major frame PC & frames counter */
695             funcs[0].pc = (void*)(uintptr_t)pc;
696             funcCnt = 1;
697         } else {
698             saveUnique = false;
699         }
700     }
701 
702     /*
703      * Temp local copy of previous backtrace value in case worker hit crashes into multiple
704      * tids for same target master thread. Will be 0 for first crash against target.
705      */
706     uint64_t oldBacktrace = run->backtrace;
707 
708     /*
709      * Calculate backtrace callstack hash signature
710      */
711     arch_hashCallstack(run, funcs, funcCnt, saveUnique);
712 
713     /*
714      * If fuzzing with sanitizer coverage feedback increase crashes counter used
715      * as metric for dynFile evolution
716      */
717     if (run->global->useSanCov) {
718         run->sanCovCnts.crashesCnt++;
719     }
720 
721     /*
722      * If unique flag is set and single frame crash, disable uniqueness for this crash
723      * to always save (timestamp will be added to the filename)
724      */
725     if (saveUnique && (funcCnt == 1)) {
726         saveUnique = false;
727     }
728 
729     /*
730      * If worker crashFileName member is set, it means that a tid has already crashed
731      * from target master thread.
732      */
733     if (run->crashFileName[0] != '\0') {
734         LOG_D("Multiple crashes detected from worker against attached tids group");
735 
736         /*
737          * If stackhashes match, don't re-analyze. This will avoid duplicates
738          * and prevent verifier from running multiple passes. Depth of check is
739          * always 1 (last backtrace saved only per target iteration).
740          */
741         if (oldBacktrace == run->backtrace) {
742             return;
743         }
744     }
745 
746     /* Increase global crashes counter */
747     ATOMIC_POST_INC(run->global->cnts.crashesCnt);
748 
749     /*
750      * Check if backtrace contains whitelisted symbol. Whitelist overrides
751      * both stackhash and symbol blacklist. Crash is always kept regardless
752      * of the status of uniqueness flag.
753      */
754     if (run->global->linux.symsWl) {
755         char* wlSymbol = arch_btContainsSymbol(
756             run->global->linux.symsWlCnt, run->global->linux.symsWl, funcCnt, funcs);
757         if (wlSymbol != NULL) {
758             saveUnique = false;
759             LOG_D("Whitelisted symbol '%s' found, skipping blacklist checks", wlSymbol);
760         }
761     } else {
762         /*
763          * Check if stackhash is blacklisted
764          */
765         if (run->global->blacklist && (fastArray64Search(run->global->blacklist,
766                                            run->global->blacklistCnt, run->backtrace) != -1)) {
767             LOG_I("Blacklisted stack hash '%" PRIx64 "', skipping", run->backtrace);
768             ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
769             return;
770         }
771 
772         /*
773          * Check if backtrace contains blacklisted symbol
774          */
775         char* blSymbol = arch_btContainsSymbol(
776             run->global->linux.symsBlCnt, run->global->linux.symsBl, funcCnt, funcs);
777         if (blSymbol != NULL) {
778             LOG_I("Blacklisted symbol '%s' found, skipping", blSymbol);
779             ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
780             return;
781         }
782     }
783 
784     /* If non-blacklisted crash detected, zero set two MSB */
785     ATOMIC_POST_ADD(run->global->dynFileIterExpire, _HF_DYNFILE_SUB_MASK);
786 
787     void* sig_addr = si.si_addr;
788     if (run->global->linux.disableRandomization == false) {
789         pc = 0UL;
790         sig_addr = NULL;
791     }
792 
793     /* User-induced signals don't set si.si_addr */
794     if (SI_FROMUSER(&si)) {
795         sig_addr = NULL;
796     }
797 
798     /* If dry run mode, copy file with same name into workspace */
799     if (run->global->mutationsPerRun == 0U && run->global->useVerifier) {
800         snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
801             run->origFileName);
802     } else if (saveUnique) {
803         snprintf(run->crashFileName, sizeof(run->crashFileName),
804             "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s",
805             run->global->io.crashDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
806             sig_addr, instr, run->global->io.fileExtn);
807     } else {
808         char localtmstr[PATH_MAX];
809         util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
810         snprintf(run->crashFileName, sizeof(run->crashFileName),
811             "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s",
812             run->global->io.crashDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
813             sig_addr, instr, localtmstr, pid, run->global->io.fileExtn);
814     }
815 
816     if (files_exists(run->crashFileName)) {
817         LOG_I("It seems that '%s' already exists, skipping", run->crashFileName);
818         // Clear filename so that verifier can understand we hit a duplicate
819         memset(run->crashFileName, 0, sizeof(run->crashFileName));
820         return;
821     }
822 
823     if (files_writeBufToFile(run->crashFileName, run->dynamicFile, run->dynamicFileSz,
824             O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC) == false) {
825         LOG_E("Couldn't copy '%s' to '%s'", run->fileName, run->crashFileName);
826         return;
827     }
828 
829     LOG_I("Ok, that's interesting, saved '%s' as '%s'", run->fileName, run->crashFileName);
830 
831     ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt);
832     /* If unique crash found, reset dynFile counter */
833     ATOMIC_CLEAR(run->global->dynFileIterExpire);
834 
835     arch_traceGenerateReport(pid, run, funcs, funcCnt, &si, instr);
836 }
837 
838 /* TODO: Add report parsing support for other sanitizers too */
arch_parseAsanReport(run_t * run,pid_t pid,funcs_t * funcs,void ** crashAddr,char ** op)839 static int arch_parseAsanReport(
840     run_t* run, pid_t pid, funcs_t* funcs, void** crashAddr, char** op) {
841     char crashReport[PATH_MAX] = {0};
842     const char* const crashReportCpy = crashReport;
843     snprintf(
844         crashReport, sizeof(crashReport), "%s/%s.%d", run->global->io.workDir, kLOGPREFIX, pid);
845 
846     FILE* fReport = fopen(crashReport, "rb");
847     if (fReport == NULL) {
848         PLOG_D("Couldn't open '%s' - R/O mode", crashReport);
849         return -1;
850     }
851     defer { fclose(fReport); };
852     defer { unlink(crashReportCpy); };
853 
854     char header[35] = {0};
855     snprintf(header, sizeof(header), "==%d==ERROR: AddressSanitizer:", pid);
856     size_t headerSz = strlen(header);
857     bool headerFound = false;
858 
859     uint8_t frameIdx = 0;
860     char framePrefix[5] = {0};
861     snprintf(framePrefix, sizeof(framePrefix), "#%" PRIu8, frameIdx);
862 
863     char *lineptr = NULL, *cAddr = NULL;
864     size_t n = 0;
865     defer { free(lineptr); };
866     for (;;) {
867         if (getline(&lineptr, &n, fReport) == -1) {
868             break;
869         }
870 
871         /* First step is to identify header */
872         if (headerFound == false) {
873             if ((strlen(lineptr) > headerSz) && (strncmp(header, lineptr, headerSz) == 0)) {
874                 headerFound = true;
875 
876                 /* Parse crash address */
877                 cAddr = strstr(lineptr, "address 0x");
878                 if (cAddr) {
879                     cAddr = cAddr + strlen("address ");
880                     char* endOff = strchr(cAddr, ' ');
881                     cAddr[endOff - cAddr] = '\0';
882                     *crashAddr = (void*)((size_t)strtoull(cAddr, NULL, 16));
883                 } else {
884                     *crashAddr = 0x0;
885                 }
886             }
887             continue;
888         } else {
889             char* pLineLC = lineptr;
890             /* Trim leading spaces */
891             while (*pLineLC != '\0' && isspace(*pLineLC)) {
892                 ++pLineLC;
893             }
894 
895             /* End separator for crash thread stack trace is an empty line */
896             if ((*pLineLC == '\0') && (frameIdx != 0)) {
897                 break;
898             }
899 
900             /* Basic length checks */
901             if (strlen(pLineLC) < 10) {
902                 continue;
903             }
904 
905             /* If available parse the type of error (READ/WRITE) */
906             if (cAddr && strstr(pLineLC, cAddr)) {
907                 if (strncmp(pLineLC, "READ", 4) == 0) {
908                     *op = "READ";
909                 } else if (strncmp(pLineLC, "WRITE", 5) == 0) {
910                     *op = "WRITE";
911                 }
912                 cAddr = NULL;
913             }
914 
915             /* Check for crash thread frames */
916             if (strncmp(pLineLC, framePrefix, strlen(framePrefix)) == 0) {
917                 /* Abort if max depth */
918                 if (frameIdx >= _HF_MAX_FUNCS) {
919                     break;
920                 }
921 
922                 /*
923                  * Frames have following format:
924                  #0 0xaa860177  (/system/lib/libc.so+0x196177)
925                  */
926                 char* savePtr = NULL;
927                 strtok_r(pLineLC, " ", &savePtr);
928                 funcs[frameIdx].pc =
929                     (void*)((size_t)strtoull(strtok_r(NULL, " ", &savePtr), NULL, 16));
930 
931                 /* DSO & code offset parsing */
932                 char* targetStr = strtok_r(NULL, " ", &savePtr);
933                 char* startOff = strchr(targetStr, '(') + 1;
934                 char* plusOff = strchr(targetStr, '+');
935                 char* endOff = strrchr(targetStr, ')');
936                 targetStr[endOff - startOff] = '\0';
937                 if ((startOff == NULL) || (endOff == NULL) || (plusOff == NULL)) {
938                     LOG_D("Invalid ASan report entry (%s)", lineptr);
939                 } else {
940                     size_t dsoSz =
941                         MIN(sizeof(funcs[frameIdx].mapName), (size_t)(plusOff - startOff));
942                     memcpy(funcs[frameIdx].mapName, startOff, dsoSz);
943                     char* codeOff = targetStr + (plusOff - startOff) + 1;
944                     funcs[frameIdx].line = strtoull(codeOff, NULL, 16);
945                 }
946 
947                 frameIdx++;
948                 snprintf(framePrefix, sizeof(framePrefix), "#%" PRIu8, frameIdx);
949             }
950         }
951     }
952 
953     return frameIdx;
954 }
955 
956 /*
957  * Special book keeping for cases where crashes are detected based on exitcode and not
958  * a raised signal. Such case is the ASan fuzzing for Android. Crash file name maintains
959  * the same format for compatibility with post campaign tools.
960  */
arch_traceExitSaveData(run_t * run,pid_t pid)961 static void arch_traceExitSaveData(run_t* run, pid_t pid) {
962     REG_TYPE pc = 0;
963     void* crashAddr = 0;
964     char* op = "UNKNOWN";
965     pid_t targetPid = (run->global->linux.pid > 0) ? run->global->linux.pid : run->pid;
966 
967     /* Save only the first hit for each worker */
968     if (run->crashFileName[0] != '\0') {
969         return;
970     }
971 
972     /* Increase global crashes counter */
973     ATOMIC_POST_INC(run->global->cnts.crashesCnt);
974     ATOMIC_POST_AND(run->global->dynFileIterExpire, _HF_DYNFILE_SUB_MASK);
975 
976     /*
977      * If fuzzing with sanitizer coverage feedback increase crashes counter used
978      * as metric for dynFile evolution
979      */
980     if (run->global->useSanCov) {
981         run->sanCovCnts.crashesCnt++;
982     }
983 
984     /* If sanitizer produces reports with stack traces (e.g. ASan), they're parsed manually */
985     int funcCnt = 0;
986     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
987     defer { free(funcs); };
988     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
989 
990     /* Sanitizers save reports against parent PID */
991     if (targetPid != pid) {
992         return;
993     }
994     funcCnt = arch_parseAsanReport(run, pid, funcs, &crashAddr, &op);
995 
996     /*
997      * -1 error indicates a file not found for report. This is expected to happen often since
998      * ASan report is generated once for crashing TID. Ptrace arch is not guaranteed to parse
999      * that TID first. Not setting the 'crashFileName' variable will ensure that this branch
1000      * is executed again for all TIDs until the matching report is found
1001      */
1002     if (funcCnt == -1) {
1003         return;
1004     }
1005 
1006     /* Since crash address is available, apply ignoreAddr filters */
1007     if (crashAddr < run->global->linux.ignoreAddr) {
1008         LOG_I("'%s' is interesting, but the crash addr is %p (below %p), skipping", run->fileName,
1009             crashAddr, run->global->linux.ignoreAddr);
1010         return;
1011     }
1012 
1013     /* If frames successfully recovered, calculate stack hash & populate crash PC */
1014     arch_hashCallstack(run, funcs, funcCnt, false);
1015     pc = (uintptr_t)funcs[0].pc;
1016 
1017     /*
1018      * Check if stackhash is blacklisted
1019      */
1020     if (run->global->blacklist && (fastArray64Search(run->global->blacklist,
1021                                        run->global->blacklistCnt, run->backtrace) != -1)) {
1022         LOG_I("Blacklisted stack hash '%" PRIx64 "', skipping", run->backtrace);
1023         ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
1024         return;
1025     }
1026 
1027     /* If dry run mode, copy file with same name into workspace */
1028     if (run->global->mutationsPerRun == 0U && run->global->useVerifier) {
1029         snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
1030             run->origFileName);
1031     } else {
1032         /* Keep the crashes file name format identical */
1033         if (run->backtrace != 0ULL && run->global->io.saveUnique) {
1034             snprintf(run->crashFileName, sizeof(run->crashFileName),
1035                 "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%s.ADDR.%p.INSTR.%s.%s",
1036                 run->global->io.crashDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
1037                 run->global->io.fileExtn);
1038         } else {
1039             /* If no stack hash available, all crashes treated as unique */
1040             char localtmstr[PATH_MAX];
1041             util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
1042             snprintf(run->crashFileName, sizeof(run->crashFileName),
1043                 "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%s.ADDR.%p.INSTR.%s.%s.%s",
1044                 run->global->io.crashDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
1045                 localtmstr, run->global->io.fileExtn);
1046         }
1047     }
1048 
1049     bool dstFileExists = false;
1050     if (files_copyFile(run->fileName, run->crashFileName, &dstFileExists, true /* try_link */)) {
1051         LOG_I("Ok, that's interesting, saved '%s' as '%s'", run->fileName, run->crashFileName);
1052 
1053         /* Increase unique crashes counters */
1054         ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt);
1055         ATOMIC_CLEAR(run->global->dynFileIterExpire);
1056     } else {
1057         if (dstFileExists) {
1058             LOG_I("It seems that '%s' already exists, skipping", run->crashFileName);
1059 
1060             /* Clear stack hash so that verifier can understand we hit a duplicate */
1061             run->backtrace = 0ULL;
1062         } else {
1063             LOG_E("Couldn't copy '%s' to '%s'", run->fileName, run->crashFileName);
1064 
1065             /* In case of write error, clear crashFileName to so that other monitored TIDs can retry
1066              */
1067             memset(run->crashFileName, 0, sizeof(run->crashFileName));
1068         }
1069 
1070         /* Don't bother generating reports for duplicate or non-saved crashes */
1071         return;
1072     }
1073 
1074     /* Generate report */
1075     run->report[0] = '\0';
1076     util_ssnprintf(run->report, sizeof(run->report), "EXIT_CODE: %s\n", HF_SAN_EXIT_CODE);
1077     util_ssnprintf(run->report, sizeof(run->report), "ORIG_FNAME: %s\n", run->origFileName);
1078     util_ssnprintf(run->report, sizeof(run->report), "FUZZ_FNAME: %s\n", run->crashFileName);
1079     util_ssnprintf(run->report, sizeof(run->report), "PID: %d\n", pid);
1080     util_ssnprintf(run->report, sizeof(run->report), "OPERATION: %s\n", op);
1081     util_ssnprintf(run->report, sizeof(run->report), "FAULT ADDRESS: %p\n", crashAddr);
1082     if (funcCnt > 0) {
1083         util_ssnprintf(run->report, sizeof(run->report), "STACK HASH: %016llx\n", run->backtrace);
1084         util_ssnprintf(run->report, sizeof(run->report), "STACK:\n");
1085         for (int i = 0; i < funcCnt; i++) {
1086             util_ssnprintf(run->report, sizeof(run->report), " <" REG_PD REG_PM "> ",
1087                 (REG_TYPE)(long)funcs[i].pc);
1088             if (funcs[i].mapName[0] != '\0') {
1089                 util_ssnprintf(run->report, sizeof(run->report), "[%s + 0x%x]\n", funcs[i].mapName,
1090                     funcs[i].line);
1091             } else {
1092                 util_ssnprintf(run->report, sizeof(run->report), "[]\n");
1093             }
1094         }
1095     }
1096 }
1097 
arch_traceExitAnalyzeData(run_t * run,pid_t pid)1098 static void arch_traceExitAnalyzeData(run_t* run, pid_t pid) {
1099     void* crashAddr = 0;
1100     char* op = "UNKNOWN";
1101     int funcCnt = 0;
1102     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
1103     defer { free(funcs); };
1104     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
1105 
1106     funcCnt = arch_parseAsanReport(run, pid, funcs, &crashAddr, &op);
1107 
1108     /*
1109      * -1 error indicates a file not found for report. This is expected to happen often since
1110      * ASan report is generated once for crashing TID. Ptrace arch is not guaranteed to parse
1111      * that TID first. Not setting the 'crashFileName' variable will ensure that this branch
1112      * is executed again for all TIDs until the matching report is found
1113      */
1114     if (funcCnt == -1) {
1115         return;
1116     }
1117 
1118     /* If frames successfully recovered, calculate stack hash & populate crash PC */
1119     arch_hashCallstack(run, funcs, funcCnt, false);
1120 }
1121 
arch_traceExitAnalyze(run_t * run,pid_t pid)1122 void arch_traceExitAnalyze(run_t* run, pid_t pid) {
1123     if (run->mainWorker) {
1124         /* Main fuzzing threads */
1125         arch_traceExitSaveData(run, pid);
1126     } else {
1127         /* Post crash analysis (e.g. crashes verifier) */
1128         arch_traceExitAnalyzeData(run, pid);
1129     }
1130 }
1131 
1132 #define __WEVENT(status) ((status & 0xFF0000) >> 16)
arch_traceEvent(run_t * run,int status,pid_t pid)1133 static void arch_traceEvent(run_t* run, int status, pid_t pid) {
1134     LOG_D("PID: %d, Ptrace event: %d", pid, __WEVENT(status));
1135     switch (__WEVENT(status)) {
1136         case PTRACE_EVENT_EXIT: {
1137             unsigned long event_msg;
1138             if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &event_msg) == -1) {
1139                 PLOG_E("ptrace(PTRACE_GETEVENTMSG,%d) failed", pid);
1140                 return;
1141             }
1142 
1143             if (WIFEXITED(event_msg)) {
1144                 LOG_D("PID: %d exited with exit_code: %lu", pid,
1145                     (unsigned long)WEXITSTATUS(event_msg));
1146                 if (WEXITSTATUS(event_msg) == (unsigned long)HF_SAN_EXIT_CODE) {
1147                     arch_traceExitAnalyze(run, pid);
1148                 }
1149             } else if (WIFSIGNALED(event_msg)) {
1150                 LOG_D(
1151                     "PID: %d terminated with signal: %lu", pid, (unsigned long)WTERMSIG(event_msg));
1152             } else {
1153                 LOG_D("PID: %d exited with unknown status: %lu", pid, event_msg);
1154             }
1155         } break;
1156         default:
1157             break;
1158     }
1159 
1160     ptrace(PTRACE_CONT, pid, 0, 0);
1161 }
1162 
arch_traceAnalyze(run_t * run,int status,pid_t pid)1163 void arch_traceAnalyze(run_t* run, int status, pid_t pid) {
1164     /*
1165      * It's a ptrace event, deal with it elsewhere
1166      */
1167     if (WIFSTOPPED(status) && __WEVENT(status)) {
1168         return arch_traceEvent(run, status, pid);
1169     }
1170 
1171     if (WIFSTOPPED(status)) {
1172         /*
1173          * If it's an interesting signal, save the testcase
1174          */
1175         if (arch_sigs[WSTOPSIG(status)].important) {
1176             /*
1177              * If fuzzer worker is from core fuzzing process run full
1178              * analysis. Otherwise just unwind and get stack hash signature.
1179              */
1180             if (run->mainWorker) {
1181                 arch_traceSaveData(run, pid);
1182             } else {
1183                 arch_traceAnalyzeData(run, pid);
1184             }
1185         }
1186         /* Do not deliver SIGSTOP, as we don't support PTRACE_LISTEN anyway */
1187         int sig = (WSTOPSIG(status) != SIGSTOP) ? WSTOPSIG(status) : 0;
1188         ptrace(PTRACE_CONT, pid, 0, sig);
1189         return;
1190     }
1191 
1192     /*
1193      * Resumed by delivery of SIGCONT
1194      */
1195     if (WIFCONTINUED(status)) {
1196         return;
1197     }
1198 
1199     /*
1200      * Process exited
1201      */
1202     if (WIFEXITED(status)) {
1203         /*
1204          * Target exited with sanitizer defined exitcode (used when SIGABRT is not monitored)
1205          */
1206         if (WEXITSTATUS(status) == (unsigned long)HF_SAN_EXIT_CODE) {
1207             arch_traceExitAnalyze(run, pid);
1208         }
1209         return;
1210     }
1211 
1212     if (WIFSIGNALED(status)) {
1213         return;
1214     }
1215 
1216     abort(); /* NOTREACHED */
1217 }
1218 
arch_listThreads(int tasks[],size_t thrSz,int pid)1219 static bool arch_listThreads(int tasks[], size_t thrSz, int pid) {
1220     char path[512];
1221     snprintf(path, sizeof(path), "/proc/%d/task", pid);
1222 
1223     /* An optimization, the number of threads is st.st_nlink - 2 (. and ..) */
1224     struct stat st;
1225     if (stat(path, &st) != -1) {
1226         if (st.st_nlink == 3) {
1227             tasks[0] = pid;
1228             tasks[1] = 0;
1229             return true;
1230         }
1231     }
1232 
1233     size_t count = 0;
1234     DIR* dir = opendir(path);
1235     if (!dir) {
1236         PLOG_E("Couldn't open dir '%s'", path);
1237         return false;
1238     }
1239     defer { closedir(dir); };
1240 
1241     for (;;) {
1242         errno = 0;
1243         struct dirent* res = readdir(dir);
1244         if (res == NULL && errno != 0) {
1245             PLOG_E("Couldn't read contents of '%s'", path);
1246             return false;
1247         }
1248 
1249         if (res == NULL) {
1250             break;
1251         }
1252 
1253         pid_t pid = (pid_t)strtol(res->d_name, (char**)NULL, 10);
1254         if (pid == 0) {
1255             LOG_D("The following dir entry couldn't be converted to pid_t '%s'", res->d_name);
1256             continue;
1257         }
1258 
1259         tasks[count++] = pid;
1260         LOG_D("Added pid '%d' from '%s/%s'", pid, path, res->d_name);
1261 
1262         if (count >= thrSz) {
1263             break;
1264         }
1265     }
1266     PLOG_D("Total number of threads in pid '%d': '%zd'", pid, count);
1267     tasks[count + 1] = 0;
1268     if (count < 1) {
1269         return false;
1270     }
1271     return true;
1272 }
1273 
arch_traceWaitForPidStop(pid_t pid)1274 bool arch_traceWaitForPidStop(pid_t pid) {
1275     for (;;) {
1276         int status;
1277         pid_t ret = wait4(pid, &status, __WALL | WUNTRACED, NULL);
1278         if (ret == -1 && errno == EINTR) {
1279             continue;
1280         }
1281         if (ret == -1) {
1282             PLOG_W("wait4(pid=%d) failed", pid);
1283             return false;
1284         }
1285         if (!WIFSTOPPED(status)) {
1286             LOG_W("PID %d not in a stopped state - status:%d", pid, status);
1287             return false;
1288         }
1289         return true;
1290     }
1291 }
1292 
1293 #define MAX_THREAD_IN_TASK 4096
arch_traceAttach(run_t * run,pid_t pid)1294 bool arch_traceAttach(run_t* run, pid_t pid) {
1295 /*
1296  * It should be present since, at least, Linux kernel 3.8, but
1297  * not always defined in kernel-headers
1298  */
1299 #if !defined(PTRACE_O_EXITKILL)
1300 #define PTRACE_O_EXITKILL (1 << 20)
1301 #endif /* !defined(PTRACE_O_EXITKILL) */
1302     long seize_options = PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK;
1303     if (run->global->linux.pid == 0) {
1304         seize_options |= PTRACE_O_EXITKILL;
1305     }
1306     /* The event is only used with sanitizers */
1307     if (run->global->enableSanitizers) {
1308         seize_options |= PTRACE_O_TRACEEXIT;
1309     }
1310 
1311     if (run->global->linux.pid == 0 && arch_traceWaitForPidStop(pid) == false) {
1312         return false;
1313     }
1314 
1315     if (ptrace(PTRACE_SEIZE, pid, NULL, seize_options) == -1) {
1316         PLOG_W("Couldn't ptrace(PTRACE_SEIZE) to pid: %d", pid);
1317         return false;
1318     }
1319 
1320     LOG_D("Attached to PID: %d", pid);
1321 
1322     /* It only makes sense to attach to threads with -p */
1323     if (run->global->linux.pid == 0) {
1324         return true;
1325     }
1326 
1327     int tasks[MAX_THREAD_IN_TASK + 1] = {0};
1328     if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, pid)) {
1329         LOG_E("Couldn't read thread list for pid '%d'", pid);
1330         return false;
1331     }
1332 
1333     for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
1334         if (tasks[i] == pid) {
1335             continue;
1336         }
1337         if (ptrace(PTRACE_SEIZE, tasks[i], NULL, seize_options) == -1) {
1338             PLOG_W("Couldn't ptrace(PTRACE_SEIZE) to pid: %d", tasks[i]);
1339             continue;
1340         }
1341         LOG_D("Attached to PID: %d (thread_group:%d)", tasks[i], pid);
1342     }
1343     return true;
1344 }
1345 
arch_traceDetach(pid_t pid)1346 void arch_traceDetach(pid_t pid) {
1347     if (syscall(__NR_kill, pid, 0) == -1 && errno == ESRCH) {
1348         LOG_D("PID: %d no longer exists", pid);
1349         return;
1350     }
1351 
1352     int tasks[MAX_THREAD_IN_TASK + 1] = {0};
1353     if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, pid)) {
1354         LOG_E("Couldn't read thread list for pid '%d'", pid);
1355         return;
1356     }
1357 
1358     for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
1359         ptrace(PTRACE_INTERRUPT, tasks[i], NULL, NULL);
1360         arch_traceWaitForPidStop(tasks[i]);
1361         ptrace(PTRACE_DETACH, tasks[i], NULL, NULL);
1362     }
1363 }
1364 
arch_traceSignalsInit(honggfuzz_t * hfuzz)1365 void arch_traceSignalsInit(honggfuzz_t* hfuzz) {
1366     /* Default is true for all platforms except Android */
1367     arch_sigs[SIGABRT].important = hfuzz->monitorSIGABRT;
1368 
1369     /* Default is false */
1370     arch_sigs[SIGVTALRM].important = hfuzz->timing.tmoutVTALRM;
1371 }
1372