blob: eb371d7355f144cbd2ba8e6ba85e95a9fb86d8a2 [file] [log] [blame]
robert.swiecki3bb518c2010-10-14 00:48:24 +00001/*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00002 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00003 * honggfuzz - architecture dependent code (LINUX/PTRACE)
4 * -----------------------------------------
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00005 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00006 * Author: Robert Swiecki <swiecki@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00007 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00008 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00009 *
10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
11 * not use this file except in compliance with the License. You may obtain
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000012 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000013 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000014 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000015 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000016 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
19 * implied. See the License for the specific language governing
20 * permissions and limitations under the License.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000021 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000022 */
robert.swiecki3bb518c2010-10-14 00:48:24 +000023
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000024#include "common.h"
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030025#include "ptrace_utils.h"
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000026
robert.swiecki3bb518c2010-10-14 00:48:24 +000027#include <ctype.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000028#include <dirent.h>
29#include <elf.h>
robert.swiecki@gmail.com4c1ad432015-02-03 11:04:13 +000030#include <endian.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000031#include <errno.h>
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000032#include <fcntl.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000033#include <signal.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <inttypes.h>
38#include <sys/cdefs.h>
39#include <sys/personality.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000040#include <sys/ptrace.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000041#include <sys/prctl.h>
42#include <sys/resource.h>
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000043#include <sys/stat.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000044#include <sys/time.h>
45#include <sys/types.h>
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +000046#include <sys/uio.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000047#include <sys/user.h>
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +000048#include <sys/wait.h>
49#include <time.h>
50#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000051
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000052#include "files.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000053#include "linux/bfd.h"
54#include "linux/unwind.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000055#include "log.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000056#include "util.h"
57
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030058#if defined(__ANDROID__)
59#include <linux/ptrace.h>
60#include <asm/ptrace.h>
61#include <sys/syscall.h>
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#define REG_TYPE uint64_t
71#define REG_PM PRIx64
72#define REG_PD "0x%016"
73#endif
74
75#if defined(__i386__) || defined(__x86_64__)
76#define MAX_INSTR_SZ 16
77#elif defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
78#define MAX_INSTR_SZ 4
79#elif defined(__aarch64__)
80#define MAX_INSTR_SZ 8
81#endif
82
83#ifdef __ANDROID__
84#ifndef WIFCONTINUED
85#define WIFCONTINUED(x) WEXITSTATUS(0)
86#endif
87#endif
88
89#if defined(__ANDROID__)
90#if defined(__NR_process_vm_readv)
91static ssize_t honggfuzz_process_vm_readv(pid_t pid,
92 const struct iovec *lvec,
93 unsigned long liovcnt,
94 const struct iovec *rvec,
95 unsigned long riovcnt,
96 unsigned long flags)
97{
98 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
99}
100# define process_vm_readv honggfuzz_process_vm_readv
101#else /* defined(__NR_process_vm_readv) */
102# define process_vm_readv(...) (errno = ENOSYS, -1)
103#endif /* !defined(__NR_process_vm_readv) */
104
105// Naming compatibilities
106#if !defined(PT_TRACE_ME)
107# define PT_TRACE_ME PTRACE_TRACEME
108#endif
109
110#if !defined(PT_READ_I)
111# define PT_READ_I PTRACE_PEEKTEXT
112#endif
113
114#if !defined(PT_READ_D)
115# define PT_READ_D PTRACE_PEEKDATA
116#endif
117
118#if !defined(PT_READ_U)
119# define PT_READ_U PTRACE_PEEKUSR
120#endif
121
122#if !defined(PT_WRITE_I)
123# define PT_WRITE_I PTRACE_POKETEXT
124#endif
125
126#if !defined(PT_WRITE_D)
127# define PT_WRITE_D PTRACE_POKEDATA
128#endif
129
130#if !defined(PT_WRITE_U)
131# define PT_WRITE_U PTRACE_POKEUSR
132#endif
133
134#if !defined(PT_CONT)
135# define PT_CONT PTRACE_CONT
136#endif
137
138#if !defined(PT_CONTINUE)
139# define PT_CONTINUE PTRACE_CONT
140#endif
141
142#if !defined(PT_KILL)
143# define PT_KILL PTRACE_KILL
144#endif
145
146#if !defined(PT_STEP)
147# define PT_STEP PTRACE_SINGLESTEP
148#endif
149
150#if !defined(PT_GETFPREGS)
151# define PT_GETFPREGS PTRACE_GETFPREGS
152#endif
153
154#if !defined(PT_ATTACH)
155# define PT_ATTACH PTRACE_ATTACH
156#endif
157
158#if !defined(PT_DETACH)
159# define PT_DETACH PTRACE_DETACH
160#endif
161
162#if !defined(PT_SYSCALL)
163# define PT_SYSCALL PTRACE_SYSCALL
164#endif
165
166#if !defined(PT_SETOPTIONS)
167# define PT_SETOPTIONS PTRACE_SETOPTIONS
168#endif
169
170#if !defined(PT_GETEVENTMSG)
171# define PT_GETEVENTMSG PTRACE_GETEVENTMSG
172#endif
173
174#if !defined(PT_GETSIGINFO)
175# define PT_GETSIGINFO PTRACE_GETSIGINFO
176#endif
177
178#if !defined(PT_SETSIGINFO)
179# define PT_SETSIGINFO PTRACE_SETSIGINFO
180#endif
181
182#endif /* defined(__ANDROID__) */
183
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000184/* *INDENT-OFF* */
robert.swiecki3bb518c2010-10-14 00:48:24 +0000185struct {
186 bool important;
187 const char *descr;
robert.swiecki@gmail.comb16e1d92015-02-03 03:46:06 +0000188} arch_sigs[NSIG] = {
189 [0 ... (NSIG - 1)].important = false,
190 [0 ... (NSIG - 1)].descr = "UNKNOWN",
191
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000192 [SIGILL].important = true,
193 [SIGILL].descr = "SIGILL",
194 [SIGFPE].important = true,
195 [SIGFPE].descr = "SIGFPE",
196 [SIGSEGV].important = true,
197 [SIGSEGV].descr = "SIGSEGV",
198 [SIGBUS].important = true,
199 [SIGBUS].descr = "SIGBUS",
200 [SIGABRT].important = true,
201 [SIGABRT].descr = "SIGABRT"
202};
203/* *INDENT-ON* */
robert.swiecki3bb518c2010-10-14 00:48:24 +0000204
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300205static size_t arch_getProcMem(pid_t pid, uint8_t * buf, size_t len, REG_TYPE pc)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000206{
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000207 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000208 * Let's try process_vm_readv first
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000209 */
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000210 const struct iovec local_iov = {
211 .iov_base = buf,
212 .iov_len = len,
213 };
214 const struct iovec remote_iov = {
215 .iov_base = (void *)(uintptr_t) pc,
216 .iov_len = len,
217 };
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000218 if (process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) == (ssize_t) len) {
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000219 return len;
220 }
221
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300222 // Debug if failed since it shouldn't happen very often
223 LOGMSG_P(l_DEBUG, "process_vm_readv() failed");
224
robert.swiecki3bb518c2010-10-14 00:48:24 +0000225 /*
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000226 * Ok, let's do it via ptrace() then.
robert.swiecki3bb518c2010-10-14 00:48:24 +0000227 * len must be aligned to the sizeof(long)
228 */
229 int cnt = len / sizeof(long);
230 size_t memsz = 0;
231
232 for (int x = 0; x < cnt; x++) {
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000233 uint8_t *addr = (uint8_t *) (uintptr_t) pc + (int)(x * sizeof(long));
robert.swiecki3bb518c2010-10-14 00:48:24 +0000234 long ret = ptrace(PT_READ_D, pid, addr, NULL);
235
236 if (errno != 0) {
237 LOGMSG_P(l_WARN, "Couldn't PT_READ_D on pid %d, addr: %p", pid, addr);
238 break;
239 }
240
241 memsz += sizeof(long);
242 memcpy(&buf[x * sizeof(long)], &ret, sizeof(long));
243 }
244 return memsz;
245}
246
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300247// Non i386 / x86_64 ISA fail build due to unused pid argument
248#pragma GCC diagnostic push
249#pragma GCC diagnostic ignored "-Wunused-parameter"
robert.swieckid3e44152015-03-16 20:02:36 +0000250uint64_t arch_ptraceGetCustomPerf(honggfuzz_t * hfuzz, pid_t pid)
robert.swiecki2a953692015-03-16 19:33:37 +0000251{
robert.swieckid3e44152015-03-16 20:02:36 +0000252 if ((hfuzz->dynFileMethod & _HF_DYNFILE_CUSTOM) == 0) {
253 return 0ULL;
254 }
robert.swiecki2a953692015-03-16 19:33:37 +0000255#if defined(__i386__) || defined(__x86_64__)
256 char buf[1024];
257 struct iovec pt_iov = {
258 .iov_base = buf,
259 .iov_len = sizeof(buf),
260 };
261 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
262 return 0ULL;
263 }
264 struct user_regs_struct_32 {
265 uint32_t ebx;
266 uint32_t ecx;
267 uint32_t edx;
268 uint32_t esi;
269 uint32_t edi;
270 uint32_t ebp;
271 uint32_t eax;
272 uint16_t ds, __ds;
273 uint16_t es, __es;
274 uint16_t fs, __fs;
275 uint16_t gs, __gs;
276 uint32_t orig_eax;
277 uint32_t eip;
278 uint16_t cs, __cs;
279 uint32_t eflags;
280 uint32_t esp;
281 uint16_t ss, __ss;
282 };
283
284 struct user_regs_struct_64 {
285 uint64_t r15;
286 uint64_t r14;
287 uint64_t r13;
288 uint64_t r12;
289 uint64_t bp;
290 uint64_t bx;
291 uint64_t r11;
292 uint64_t r10;
293 uint64_t r9;
294 uint64_t r8;
295 uint64_t ax;
296 uint64_t cx;
297 uint64_t dx;
298 uint64_t si;
299 uint64_t di;
300 uint64_t orig_ax;
301 uint64_t ip;
302 uint64_t cs;
303 uint64_t flags;
304 uint64_t sp;
305 uint64_t ss;
306 uint64_t fs_base;
307 uint64_t gs_base;
308 uint64_t ds;
309 uint64_t es;
310 uint64_t fs;
311 uint64_t gs;
312 };
313
314 /*
315 * 32-bit
316 */
317 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
318 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
319 return (uint64_t) r32->gs;
320 }
321 /*
322 * 64-bit
323 */
324 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
325 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
326 return (uint64_t) r64->gs_base;
327 }
328 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
329#endif
330 return 0ULL;
331}
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300332#pragma GCC diagnostic pop
robert.swiecki2a953692015-03-16 19:33:37 +0000333
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300334static bool arch_getPC(pid_t pid, REG_TYPE *pc, REG_TYPE *status_reg)
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000335{
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000336 char buf[1024];
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000337 struct iovec pt_iov = {
338 .iov_base = buf,
339 .iov_len = sizeof(buf),
340 };
robert.swiecki@gmail.com8a7d6982015-02-01 15:59:45 +0000341 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000342 LOGMSG_P(l_WARN, "ptrace(PTRACE_GETREGSET) failed");
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000343 return false;
344 }
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000345#if defined(__i386__) || defined(__x86_64__)
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000346 struct user_regs_struct_32 {
347 uint32_t ebx;
348 uint32_t ecx;
349 uint32_t edx;
350 uint32_t esi;
351 uint32_t edi;
352 uint32_t ebp;
353 uint32_t eax;
354 uint16_t ds, __ds;
355 uint16_t es, __es;
356 uint16_t fs, __fs;
357 uint16_t gs, __gs;
358 uint32_t orig_eax;
359 uint32_t eip;
360 uint16_t cs, __cs;
361 uint32_t eflags;
362 uint32_t esp;
363 uint16_t ss, __ss;
364 };
365
366 struct user_regs_struct_64 {
367 uint64_t r15;
368 uint64_t r14;
369 uint64_t r13;
370 uint64_t r12;
371 uint64_t bp;
372 uint64_t bx;
373 uint64_t r11;
374 uint64_t r10;
375 uint64_t r9;
376 uint64_t r8;
377 uint64_t ax;
378 uint64_t cx;
379 uint64_t dx;
380 uint64_t si;
381 uint64_t di;
382 uint64_t orig_ax;
383 uint64_t ip;
384 uint64_t cs;
385 uint64_t flags;
386 uint64_t sp;
387 uint64_t ss;
388 uint64_t fs_base;
389 uint64_t gs_base;
390 uint64_t ds;
391 uint64_t es;
392 uint64_t fs;
393 uint64_t gs;
394 };
395
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000396 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000397 * 32-bit
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000398 */
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000399 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
400 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000401 *pc = r32->eip;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300402 *status_reg = r32->eflags;
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000403 return true;
404 }
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000405 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000406 * 64-bit
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000407 */
robert.swiecki@gmail.comae20f602015-02-01 22:17:40 +0000408 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
409 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000410 *pc = r64->ip;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300411 *status_reg = r64->flags;
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000412 return true;
413 }
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000414 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000415 return false;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000416#endif /* defined(__i386__) ||
417 * defined(__x86_64__) */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000418#if defined(__arm__)
419 struct user_regs_struct_32 {
420 uint32_t uregs[18];
421 };
422 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
423 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300424
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000425#ifndef ARM_pc
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300426#ifdef __ANDROID__ /* Building with NDK headers */
427#define ARM_pc uregs[15]
428#else /* Building with glibc headers */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000429#define ARM_pc 15
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300430#endif
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000431#endif /* ARM_pc */
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300432
433#ifdef __ANDROID__
434 *pc = r32->ARM_pc;
435 *status_reg = r32->ARM_cpsr;
436#else
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000437 *pc = r32->uregs[ARM_pc];
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300438 *status_reg = r32->uregs[ARM_cpsr];
439#endif
440
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000441 return true;
442 }
443 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
444 return false;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000445#endif /* defined(__arm__) */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000446#if defined(__aarch64__)
447 struct user_regs_struct_64 {
448 uint64_t regs[31];
449 uint64_t sp;
450 uint64_t pc;
451 uint64_t pstate;
452 };
453 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
454 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000455 *pc = r64->pc;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300456 *status_reg = r64->pstate;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000457 return true;
458 }
459 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
460 return false;
461#endif /* defined(__aarch64__) */
462#if defined(__powerpc64__) || defined(__powerpc__)
463 struct user_regs_struct_32 {
464 uint32_t gpr[32];
465 uint32_t nip;
466 uint32_t msr;
467 uint32_t orig_gpr3;
468 uint32_t ctr;
469 uint32_t link;
470 uint32_t xer;
471 uint32_t ccr;
472 uint32_t mq;
473 uint32_t trap;
474 uint32_t dar;
475 uint32_t dsisr;
476 uint32_t result;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000477 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000478 * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
479 * with some zeros
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000480 */
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000481 uint32_t zero0;
482 uint32_t zero1;
483 uint32_t zero2;
484 uint32_t zero3;
485 };
486 struct user_regs_struct_64 {
487 uint64_t gpr[32];
488 uint64_t nip;
489 uint64_t msr;
490 uint64_t orig_gpr3;
491 uint64_t ctr;
492 uint64_t link;
493 uint64_t xer;
494 uint64_t ccr;
495 uint64_t softe;
496 uint64_t trap;
497 uint64_t dar;
498 uint64_t dsisr;
499 uint64_t result;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000500 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000501 * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
502 * with some zeros
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000503 */
robert.swiecki@gmail.com7e818512015-02-02 01:59:47 +0000504 uint64_t zero0;
505 uint64_t zero1;
506 uint64_t zero2;
507 uint64_t zero3;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000508 };
509 if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
510 struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000511 *pc = r32->nip;
512 return true;
513 }
514 if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
515 struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
robert.swiecki@gmail.com730f9482015-02-02 01:39:49 +0000516 *pc = r64->nip;
517 return true;
518 }
519 LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
520 return false;
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000521#endif /* defined(__powerpc64__) ||
522 * defined(__powerpc__) */
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000523 LOGMSG(l_DEBUG, "Unknown/unsupported CPU architecture");
524 return false;
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000525}
526
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300527static void arch_getInstrStr(pid_t pid, REG_TYPE *pc, char *instr)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000528{
529 /*
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000530 * We need a value aligned to 8
robert.swiecki3bb518c2010-10-14 00:48:24 +0000531 * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
532 */
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300533 uint8_t buf[MAX_INSTR_SZ];
robert.swiecki3bb518c2010-10-14 00:48:24 +0000534 size_t memsz;
535
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300536 REG_TYPE status_reg = 0;
537
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000538 snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000539
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300540 if (!arch_getPC(pid, pc, &status_reg)) {
robert.swiecki@gmail.com34a40702015-02-02 20:43:27 +0000541 LOGMSG(l_WARN, "Current architecture not supported for disassembly");
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000542 return;
543 }
544
545 if ((memsz = arch_getProcMem(pid, buf, sizeof(buf), *pc)) == 0) {
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000546 snprintf(instr, _HF_INSTR_SZ, "%s", "[NOT_MMAPED]");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000547 return;
548 }
549
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300550#if !defined(__ANDROID__)
robert.swiecki@gmail.com26eee242015-02-16 12:21:36 +0000551 arch_bfdDisasm(pid, buf, memsz, instr);
robert.swiecki@gmail.comec3acc52015-02-01 15:35:55 +0000552
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300553#else
554#if defined(__arm__)
555 cs_arch arch = CS_ARCH_ARM;
556 cs_mode mode = (status_reg & 0x20) ? CS_MODE_THUMB : CS_MODE_ARM;
557#elif defined(__aarch64__)
558 // We shouldn't need any execution detection logic here
559 cs_arch arch = CS_ARCH_ARM64;
560 cs_mode mode = CS_MODE_ARM;
561#elif defined(__i386__)
562 cs_arch arch = CS_ARCH_X86;
563 cs_mode mode = CS_MODE_32;
564#elif defined(__x86_64__)
565 cs_arch arch = CS_ARCH_X86;
566 cs_mode mode = CS_MODE_64;
567#else
568 LOGMSG(l_ERROR, "Unknown/unsupported Android CPU architecture");
569#endif
570
571 csh handle;
572 cs_err err = cs_open(arch, mode, &handle);
573 if (err != CS_ERR_OK) {
574 LOGMSG(l_WARN, "Capstone initilization failed: '%s'", cs_strerror(err));
575 return;
576 }
577
578 cs_insn *insn;
579 size_t count = cs_disasm(handle, buf, sizeof(buf), *pc, 0, &insn);
580
581 if (count < 1) {
582 LOGMSG(l_WARN, "Couldn't disassemble the assembler instructions' stream: '%s'",
583 cs_strerror(cs_errno(handle)));
584 cs_close(&handle);
585 return;
586 }
587
588 snprintf(instr, _HF_INSTR_SZ, "%s %s", insn[0].mnemonic, insn[0].op_str);
589 cs_free(insn, count);
590 cs_close(&handle);
591#endif
592
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000593 for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000594 if (instr[x] == '/' || instr[x] == '\\' || isspace(instr[x])
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +0000595 || !isprint(instr[x])) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000596 instr[x] = '_';
597 }
598 }
robert.swiecki@gmail.com26eee242015-02-16 12:21:36 +0000599
600 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000601}
602
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000603static void
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000604arch_ptraceGenerateReport(pid_t pid, fuzzer_t * fuzzer, funcs_t * funcs,
605 size_t funcCnt, siginfo_t * si, const char *instr)
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000606{
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000607 fuzzer->report[0] = '\0';
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000608 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "ORIG_FNAME: %s\n",
609 fuzzer->origFileName);
610 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "FUZZ_FNAME: %s\n", fuzzer->fileName);
611 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "PID: %d\n", pid);
612 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "SIGNAL: %s (%d)\n",
613 arch_sigs[si->si_signo].descr, si->si_signo);
614 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "FAULT ADDRESS: %p\n", si->si_addr);
615 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "INSTRUCTION: %s\n", instr);
616 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "STACK:\n");
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000617 for (size_t i = 0; i < funcCnt; i++) {
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300618#ifdef __HF_USE_CAPSTONE__
619 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <"REG_PD REG_PM "> ",
620 (REG_TYPE) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
621 if (funcs[i].func[0] != '\0')
622 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "[%s + 0x%x]\n",
623 funcs[i].func, funcs[i].line);
624 else
625 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "[]\n");
626#else
627 util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <"REG_PD REG_PM "> [%s():%u]\n",
628 (REG_TYPE) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
629#endif
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000630 }
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000631
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000632 return;
633}
634
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000635static void arch_ptraceSaveData(honggfuzz_t * hfuzz, pid_t pid, fuzzer_t * fuzzer)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000636{
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300637 REG_TYPE pc = 0;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000638
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000639 char instr[_HF_INSTR_SZ] = "\x00";
robert.swiecki3bb518c2010-10-14 00:48:24 +0000640 siginfo_t si;
641
642 if (ptrace(PT_GETSIGINFO, pid, 0, &si) == -1) {
643 LOGMSG_P(l_WARN, "Couldn't get siginfo for pid %d", pid);
644 return;
645 }
646
robert.swiecki@gmail.com12fbf542015-02-01 20:01:46 +0000647 arch_getInstrStr(pid, &pc, instr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000648
649 LOGMSG(l_DEBUG,
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000650 "Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %"
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300651 REG_PM ", instr: '%s'", pid, si.si_signo, si.si_errno, si.si_code, si.si_addr, pc,
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000652 instr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000653
robert.swiecki3bb518c2010-10-14 00:48:24 +0000654 if (si.si_addr < hfuzz->ignoreAddr) {
655 LOGMSG(l_INFO,
656 "'%s' is interesting (%s), but the si.si_addr is %p (below %p), skipping",
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000657 fuzzer->fileName, arch_sigs[si.si_signo].descr, si.si_addr, hfuzz->ignoreAddr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000658 return;
659 }
660
661 char newname[PATH_MAX];
662 if (hfuzz->saveUnique) {
663 snprintf(newname, sizeof(newname),
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300664 "%s.PC.%" REG_PM ".CODE.%d.ADDR.%p.INSTR.%s.%s.%s",
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000665 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
666 instr, fuzzer->origFileName, hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000667 } else {
668 char localtmstr[PATH_MAX];
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000669 util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr));
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000670 snprintf(newname, sizeof(newname),
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300671 "%s.PC.%" REG_PM ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s.%s",
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000672 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
673 instr, localtmstr, pid, fuzzer->origFileName, hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000674 }
675
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000676 if (link(fuzzer->fileName, newname) == 0) {
677 LOGMSG(l_INFO, "Ok, that's interesting, saved '%s' as '%s'", fuzzer->fileName, newname);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000678 } else {
679 if (errno == EEXIST) {
680 LOGMSG(l_INFO, "It seems that '%s' already exists, skipping", newname);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300681 // Don't bother unwinding & generating reports for duplicate crashes
682 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000683 } else {
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000684 LOGMSG_P(l_ERROR, "Couldn't link '%s' to '%s'", fuzzer->fileName, newname);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000685 }
686 }
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +0000687
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000688 funcs_t funcs[_HF_MAX_FUNCS] = {
689 [0 ... (_HF_MAX_FUNCS - 1)].pc = NULL,
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000690 [0 ... (_HF_MAX_FUNCS - 1)].line = 0,
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000691 [0 ... (_HF_MAX_FUNCS - 1)].func = {'\0'}
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000692 ,
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000693 };
694
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300695#if !defined(__ANDROID__)
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000696 size_t funcCnt = arch_unwindStack(pid, funcs);
697 arch_bfdResolveSyms(pid, funcs, funcCnt);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300698#else
699 size_t funcCnt = arch_unwindStack(pid, funcs);
700#endif
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000701
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000702 arch_ptraceGenerateReport(pid, fuzzer, funcs, funcCnt, &si, instr);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000703}
704
Jaggera5a5c7b2015-06-28 16:39:46 +0200705#define __WEVENT(status) ((status & 0xFF0000) >> 16)
706static void arch_ptraceEvent(int status, pid_t pid)
707{
708 LOGMSG(l_DEBUG, "PID: %d, Ptrace event %d", pid, __WEVENT(status));
709 ptrace(PT_CONTINUE, pid, 0, 0);
710 return;
711}
712
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000713void arch_ptraceAnalyze(honggfuzz_t * hfuzz, int status, pid_t pid, fuzzer_t * fuzzer)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000714{
715 /*
Jaggera5a5c7b2015-06-28 16:39:46 +0200716 * It's a ptrace event, deal with it elsewhere
robert.swiecki3bb518c2010-10-14 00:48:24 +0000717 */
Jaggera5a5c7b2015-06-28 16:39:46 +0200718 if (WIFSTOPPED(status) && __WEVENT(status)) {
719 return arch_ptraceEvent(status, pid);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000720 }
721
Jaggera5a5c7b2015-06-28 16:39:46 +0200722 if (WIFSTOPPED(status)) {
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300723 int curStatus = WSTOPSIG(status);
724
Jaggera5a5c7b2015-06-28 16:39:46 +0200725 /*
726 * If it's an interesting signal, save the testcase
727 */
728 if (arch_sigs[WSTOPSIG(status)].important) {
729 arch_ptraceSaveData(hfuzz, pid, fuzzer);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300730
731 /*
732 * An kind of ugly (although necessary) hack due to custom signal handlers
733 * in Android from debuggerd. If we pass one of the monitored signals,
734 * we'll end-up running the processing routine twice. A cost that we
735 * don't want to pay.
736 */
737#if defined(__ANDROID__)
738 curStatus = SIGINT;
739#endif
Jaggera5a5c7b2015-06-28 16:39:46 +0200740 }
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300741 ptrace(PT_CONTINUE, pid, 0, curStatus);
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000742 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000743 }
744
745 /*
746 * Resumed by delivery of SIGCONT
747 */
748 if (WIFCONTINUED(status)) {
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000749 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000750 }
751
752 /*
robert.swiecki@gmail.com124ba812011-06-22 15:51:56 +0000753 * Process exited
robert.swiecki3bb518c2010-10-14 00:48:24 +0000754 */
robert.swiecki@gmail.com124ba812011-06-22 15:51:56 +0000755 if (WIFEXITED(status) || WIFSIGNALED(status)) {
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000756 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000757 }
758
759 abort(); /* NOTREACHED */
robert.swiecki@gmail.com22e66a92015-02-18 19:54:26 +0000760 return;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000761}
762
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000763static bool arch_listThreads(int tasks[], size_t thrSz, int pid)
764{
765 size_t count = 0;
766 char path[512];
767 snprintf(path, sizeof(path), "/proc/%d/task", pid);
768 DIR *dir = opendir(path);
769 if (!dir) {
770 LOGMSG_P(l_ERROR, "Couldn't open dir '%s'", path);
771 return false;
772 }
773
774 for (;;) {
775 struct dirent de, *res;
776 if (readdir_r(dir, &de, &res) > 0) {
777 LOGMSG_P(l_ERROR, "Couldn't read contents of '%s'", path);
778 closedir(dir);
779 return false;
780 }
781
782 if (res == NULL) {
783 break;
784 }
785
786 pid_t pid = (pid_t) strtol(res->d_name, (char **)NULL, 10);
787 if (pid == 0) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000788 LOGMSG(l_DEBUG, "The following dir entry couldn't be converted to pid_t '%s'",
789 res->d_name);
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000790 continue;
791 }
792
793 tasks[count++] = pid;
794 LOGMSG(l_DEBUG, "Added pid '%d' from '%s/%s'", pid, path, res->d_name);
795
796 if (count >= thrSz) {
797 break;
798 }
799 }
800 closedir(dir);
801 LOGMSG_P(l_DEBUG, "Total number of threads in pid '%d': '%d'", pid, count);
802 tasks[count + 1] = 0;
803 if (count < 1) {
804 return false;
805 }
806 return true;
807}
808
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000809bool arch_ptraceAttach(pid_t pid)
robert.swiecki28cba5c2011-06-22 01:38:55 +0000810{
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000811#define MAX_THREAD_IN_TASK 4096
812 int tasks[MAX_THREAD_IN_TASK + 1];
813 tasks[MAX_THREAD_IN_TASK] = 0;
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000814 if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, pid)) {
815 LOGMSG(l_ERROR, "Couldn't read thread list for pid '%d'", pid);
robert.swiecki28cba5c2011-06-22 01:38:55 +0000816 return false;
817 }
818
robert.swiecki@gmail.com5f667522011-06-28 13:50:44 +0000819 for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
Jaggera5a5c7b2015-06-28 16:39:46 +0200820 if (ptrace
821 (PTRACE_SEIZE, tasks[i], NULL,
822 PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXIT) ==
823 -1) {
824 LOGMSG_P(l_ERROR, "Couldn't ptrace(PTRACE_SEIZE) to pid: %d", tasks[i]);
robert.swiecki@gmail.com3b4256d2015-02-13 17:22:41 +0000825 return false;
826 }
robert.swiecki@gmail.com7e4d0c52015-03-12 02:17:15 +0000827 LOGMSG(l_DEBUG, "Successfully attached to pid/tid: %d", tasks[i]);
robert.swiecki28cba5c2011-06-22 01:38:55 +0000828 }
Jagger7faf6f42015-06-28 14:23:26 +0200829 for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
Jaggera5a5c7b2015-06-28 16:39:46 +0200830 ptrace(PT_CONTINUE, tasks[i], NULL, NULL);
Jagger7faf6f42015-06-28 14:23:26 +0200831 }
robert.swiecki28cba5c2011-06-22 01:38:55 +0000832 return true;
833}