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