blob: 627156687b587c248bc3b3ec7b2b94e1ad8901ce [file] [log] [blame]
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +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)
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.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000023
24#include "common.h"
25#include "arch.h"
26
27#include <ctype.h>
28#include <errno.h>
29#include <signal.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <inttypes.h>
34#include <sys/cdefs.h>
35#include <sys/personality.h>
36#include <sys/ptrace.h>
37#include <sys/prctl.h>
38#include <sys/resource.h>
39#include <sys/stat.h>
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +000040#include <sys/syscall.h>
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000041#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/user.h>
44#include <sys/wait.h>
45#include <time.h>
46#include <unistd.h>
47
robert.swiecki@gmail.com6310b112015-02-17 23:30:45 +000048#include "linux/perf.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000049#include "linux/ptrace.h"
50#include "log.h"
51#include "util.h"
52
53bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
54{
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000055 /*
56 * Kill a process which corrupts its own heap (with ABRT)
57 */
58 if (setenv("MALLOC_CHECK_", "3", 1) == -1) {
59 LOGMSG_P(l_ERROR, "setenv(MALLOC_CHECK_=3) failed");
60 return false;
61 }
62
63 /*
64 * Tell asan to ignore SEGVs
65 */
robert.swiecki@gmail.com03770092015-02-20 13:48:31 +000066 if (setenv
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +000067 ("ASAN_OPTIONS",
68 "allow_user_segv_handler=1:handle_segv=0:abort_on_error=1:allocator_may_return_null=1",
69 1) == -1) {
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000070 LOGMSG_P(l_ERROR, "setenv(ASAN_OPTIONS) failed");
71 return false;
72 }
73
74 /*
75 * Kill the children when fuzzer dies (e.g. due to Ctrl+C)
76 */
77 if (prctl(PR_SET_PDEATHSIG, (long)SIGKILL, 0L, 0L, 0L) == -1) {
78 LOGMSG_P(l_ERROR, "prctl(PR_SET_PDEATHSIG, SIGKILL) failed");
79 return false;
80 }
81
82 /*
83 * Disable ASLR
84 */
85 if (personality(ADDR_NO_RANDOMIZE) == -1) {
86 LOGMSG_P(l_ERROR, "personality(ADDR_NO_RANDOMIZE) failed");
87 return false;
88 }
89#define ARGS_MAX 512
90 char *args[ARGS_MAX + 2];
91
92 int x;
93
94 for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
95 if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
96 args[x] = fileName;
97 } else {
98 args[x] = hfuzz->cmdline[x];
99 }
100 }
101
102 args[x++] = NULL;
103
104 LOGMSG(l_DEBUG, "Launching '%s' on file '%s'", args[0], fileName);
105
106 /*
107 * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
108 */
109 if (hfuzz->tmOut) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000110 /*
111 * Set the CPU rlimit to twice the value of the time-out
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000112 */
113 struct rlimit rl = {
114 .rlim_cur = hfuzz->tmOut * 2,
115 .rlim_max = hfuzz->tmOut * 2,
116 };
117 if (setrlimit(RLIMIT_CPU, &rl) == -1) {
118 LOGMSG_P(l_ERROR, "Couldn't enforce the RLIMIT_CPU resource limit");
119 return false;
120 }
121 }
122
123 /*
124 * The address space limit. If big enough - roughly the size of RAM used
125 */
126 if (hfuzz->asLimit) {
127 struct rlimit rl = {
128 .rlim_cur = hfuzz->asLimit * 1024UL * 1024UL,
129 .rlim_max = hfuzz->asLimit * 1024UL * 1024UL,
130 };
131 if (setrlimit(RLIMIT_AS, &rl) == -1) {
132 LOGMSG_P(l_DEBUG, "Couldn't encforce the RLIMIT_AS resource limit, ignoring");
133 }
134 }
135
136 if (hfuzz->nullifyStdio) {
137 util_nullifyStdio();
138 }
139
140 if (hfuzz->fuzzStdin) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000141 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000142 * Uglyyyyyy ;)
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000143 */
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000144 if (!util_redirectStdin(fileName)) {
145 return false;
146 }
147 }
148
robert.swiecki@gmail.comda8396c2015-03-04 01:42:09 +0000149 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs) && hfuzz->envs[i]; i++) {
robert.swiecki@gmail.com15eca6f2015-03-04 03:31:36 +0000150 putenv(hfuzz->envs[i]);
robert.swiecki@gmail.comda8396c2015-03-04 01:42:09 +0000151 }
152
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000153/*
154 * Wait for the ptrace to attach
155 */
156 syscall(__NR_tkill, syscall(__NR_gettid), SIGSTOP);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000157 execvp(args[0], args);
158
159 util_recoverStdio();
160 LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
161 return false;
162}
163
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000164static void arch_sigFunc(int signo, siginfo_t * si, void *dummy)
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000165{
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000166 if (signo != SIGALRM) {
167 LOGMSG(l_ERROR, "Signal != SIGALRM (%d)", signo);
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000168 }
169 return;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000170 if (si == NULL) {
171 return;
172 }
173 if (dummy == NULL) {
174 return;
175 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000176}
177
178static void arch_setTimer(void)
179{
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000180 timer_t timerid;
181 struct sigevent sevp = {
182 .sigev_value.sival_ptr = &timerid,
183 .sigev_signo = SIGALRM,
184 .sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL,
185 ._sigev_un._tid = syscall(__NR_gettid),
186 };
187 if (timer_create(CLOCK_REALTIME, &sevp, &timerid) == -1) {
188 LOGMSG_P(l_ERROR, "timer_create(CLOCK_REALTIME) failed");
189 return;
190 }
191 /*
192 * Kick in every 200ms, starting with the next second
193 */
194 const struct itimerspec ts = {
195 .it_value = {.tv_sec = 1,.tv_nsec = 0},
196 .it_interval = {.tv_sec = 0,.tv_nsec = 200000000,},
197 };
198 if (timer_settime(timerid, 0, &ts, NULL) == -1) {
199 LOGMSG_P(l_ERROR, "timer_settime() failed");
200 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000201 sigset_t smask;
202 sigemptyset(&smask);
203 struct sigaction sa = {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000204 .sa_handler = NULL,
205 .sa_sigaction = arch_sigFunc,
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000206 .sa_mask = smask,
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000207 .sa_flags = SA_SIGINFO,
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000208 .sa_restorer = NULL,
209 };
210 if (sigaction(SIGALRM, &sa, NULL) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000211 LOGMSG_P(l_ERROR, "sigaciton(SIGALRM) failed");
212 return;
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000213 }
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000214
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000215 return;
216}
217
218static void arch_checkTimeLimit(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
219{
robert.swiecki@gmail.com3213a112015-03-12 01:42:02 +0000220 int64_t curMillis = util_timeNowMillis();
221 int64_t diffMillis = curMillis - fuzzer->timeStartedMillis;
222 if (diffMillis > (hfuzz->tmOut * 1000)) {
223 LOGMSG(l_WARN, "PID %d took too much time (limit %ld s). Sending SIGKILL",
224 fuzzer->pid, hfuzz->tmOut);
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000225 kill(fuzzer->pid, SIGKILL);
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000226 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000227}
228
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000229void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
230{
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000231 arch_setTimer();
232
robert.swiecki@gmail.com10e69b62015-03-08 02:21:56 +0000233 int perfFd[3];
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000234 if (hfuzz->pid == 0) {
235 int status;
236 pid_t pid = wait4(fuzzer->pid, &status, __WNOTHREAD | __WALL | WUNTRACED, NULL);
237 if (pid != pid) {
238 LOGMSG(l_FATAL, "wait4() =! pid (%d)", fuzzer->pid);
239 }
240 if (!WIFSTOPPED(status)) {
241 LOGMSG(l_FATAL, "PID '%d' is not in a stopped state", fuzzer->pid);
242 }
243 if (arch_ptraceAttach(fuzzer->pid) == false) {
244 LOGMSG(l_FATAL, "Couldn't attach to pid %d", fuzzer->pid);
245 }
246 if (arch_perfEnable(fuzzer->pid, hfuzz, perfFd) == false) {
247 LOGMSG(l_FATAL, "Couldn't enable perf counters for pid %d", fuzzer->pid);
248 }
249 arch_ptraceAnalyze(hfuzz, status, fuzzer->pid, fuzzer);
robert.swiecki@gmail.com627c1932015-02-25 02:35:00 +0000250 }
robert.swiecki@gmail.comd7818972015-02-24 23:37:59 +0000251
252 for (;;) {
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000253 int status;
robert.swiecki@gmail.comc471a9f2015-02-25 17:28:06 +0000254 pid_t pid = wait3(&status, __WNOTHREAD | __WALL | WUNTRACED, NULL);
robert.swiecki@gmail.com6e3d04c2015-02-25 02:04:15 +0000255
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000256 LOGMSG(l_DEBUG, "PID '%d' returned with status '%d'", pid, status);
robert.swiecki@gmail.comd7818972015-02-24 23:37:59 +0000257
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000258 if (pid == -1 && errno == EINTR) {
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000259 arch_checkTimeLimit(hfuzz, fuzzer);
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000260 continue;
261 }
262 if (pid == -1 && errno == ECHILD) {
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000263 if (hfuzz->pid == 0) {
264 arch_perfAnalyze(hfuzz, fuzzer, perfFd);
265 }
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000266 LOGMSG(l_DEBUG, "No more processes to track");
267 return;
268 }
269 if (pid == -1) {
270 LOGMSG_P(l_FATAL, "wait3() failed");
271 return;
272 }
273
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000274 if (hfuzz->pid == 0) {
275 arch_ptraceAnalyze(hfuzz, status, pid, fuzzer);
276 }
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000277 }
278}
279
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000280bool arch_archInit(honggfuzz_t * hfuzz)
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000281{
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000282 return arch_ptracePrepare(hfuzz);
283}