blob: fffd4bc713fd043b4cf240e396c6eb6398ea9a35 [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"
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030049#include "linux/ptrace_utils.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000050#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];
Anestis Bechtsoudisc1f6faa2015-07-31 05:32:19 +030091 char argData[PATH_MAX] = { 0 };
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000092 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;
Anestis Bechtsoudisc1f6faa2015-07-31 05:32:19 +030097 } else if (!hfuzz->fuzzStdin && strstr(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER)) {
98 const char *off = strstr(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER);
99 snprintf(argData, PATH_MAX, "%.*s%s", (int)(off - hfuzz->cmdline[x]), hfuzz->cmdline[x], fileName);
100 args[x] = argData;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000101 } else {
102 args[x] = hfuzz->cmdline[x];
103 }
104 }
105
106 args[x++] = NULL;
107
108 LOGMSG(l_DEBUG, "Launching '%s' on file '%s'", args[0], fileName);
109
110 /*
111 * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
112 */
113 if (hfuzz->tmOut) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000114 /*
115 * Set the CPU rlimit to twice the value of the time-out
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000116 */
117 struct rlimit rl = {
118 .rlim_cur = hfuzz->tmOut * 2,
119 .rlim_max = hfuzz->tmOut * 2,
120 };
121 if (setrlimit(RLIMIT_CPU, &rl) == -1) {
122 LOGMSG_P(l_ERROR, "Couldn't enforce the RLIMIT_CPU resource limit");
123 return false;
124 }
125 }
126
127 /*
128 * The address space limit. If big enough - roughly the size of RAM used
129 */
130 if (hfuzz->asLimit) {
131 struct rlimit rl = {
132 .rlim_cur = hfuzz->asLimit * 1024UL * 1024UL,
133 .rlim_max = hfuzz->asLimit * 1024UL * 1024UL,
134 };
135 if (setrlimit(RLIMIT_AS, &rl) == -1) {
136 LOGMSG_P(l_DEBUG, "Couldn't encforce the RLIMIT_AS resource limit, ignoring");
137 }
138 }
139
robert.swiecki3da0ea52015-03-12 14:19:45 +0000140 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs) && hfuzz->envs[i]; i++) {
141 putenv(hfuzz->envs[i]);
142 }
143
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000144 if (hfuzz->nullifyStdio) {
145 util_nullifyStdio();
146 }
147
148 if (hfuzz->fuzzStdin) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000149 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000150 * Uglyyyyyy ;)
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000151 */
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000152 if (!util_redirectStdin(fileName)) {
153 return false;
154 }
155 }
robert.swiecki3da0ea52015-03-12 14:19:45 +0000156 /*
157 * Wait for the ptrace to attach
158 */
robert.swiecki@gmail.com59ca7eb2015-04-02 02:25:22 +0000159 syscall(__NR_tkill, syscall(__NR_gettid), SIGSTOP);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000160 execvp(args[0], args);
161
162 util_recoverStdio();
163 LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
164 return false;
165}
166
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000167static void arch_sigFunc(int signo, siginfo_t * si, void *dummy)
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000168{
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000169 if (signo != SIGALRM) {
170 LOGMSG(l_ERROR, "Signal != SIGALRM (%d)", signo);
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000171 }
172 return;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000173 if (si == NULL) {
174 return;
175 }
176 if (dummy == NULL) {
177 return;
178 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000179}
180
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000181static void arch_removeTimer(timer_t * timerid)
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000182{
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000183 timer_delete(*timerid);
184}
185
186static bool arch_setTimer(timer_t * timerid)
187{
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000188 struct sigevent sevp = {
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000189 .sigev_value.sival_ptr = timerid,
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000190 .sigev_signo = SIGALRM,
191 .sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL,
192 ._sigev_un._tid = syscall(__NR_gettid),
193 };
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000194 if (timer_create(CLOCK_REALTIME, &sevp, timerid) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000195 LOGMSG_P(l_ERROR, "timer_create(CLOCK_REALTIME) failed");
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000196 return false;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000197 }
198 /*
199 * Kick in every 200ms, starting with the next second
200 */
201 const struct itimerspec ts = {
202 .it_value = {.tv_sec = 1,.tv_nsec = 0},
203 .it_interval = {.tv_sec = 0,.tv_nsec = 200000000,},
204 };
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000205 if (timer_settime(*timerid, 0, &ts, NULL) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000206 LOGMSG_P(l_ERROR, "timer_settime() failed");
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000207 timer_delete(*timerid);
208 return false;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000209 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000210 sigset_t smask;
211 sigemptyset(&smask);
212 struct sigaction sa = {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000213 .sa_handler = NULL,
214 .sa_sigaction = arch_sigFunc,
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000215 .sa_mask = smask,
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000216 .sa_flags = SA_SIGINFO,
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000217 .sa_restorer = NULL,
218 };
219 if (sigaction(SIGALRM, &sa, NULL) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000220 LOGMSG_P(l_ERROR, "sigaciton(SIGALRM) failed");
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000221 return false;
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000222 }
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000223
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000224 return true;
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000225}
226
227static void arch_checkTimeLimit(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
228{
robert.swiecki@gmail.com3213a112015-03-12 01:42:02 +0000229 int64_t curMillis = util_timeNowMillis();
230 int64_t diffMillis = curMillis - fuzzer->timeStartedMillis;
231 if (diffMillis > (hfuzz->tmOut * 1000)) {
232 LOGMSG(l_WARN, "PID %d took too much time (limit %ld s). Sending SIGKILL",
233 fuzzer->pid, hfuzz->tmOut);
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000234 kill(fuzzer->pid, SIGKILL);
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000235 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000236}
237
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000238void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
239{
robert.swiecki@gmail.com57573b82015-04-02 00:26:35 +0000240 pid_t ptracePid = (hfuzz->pid > 0) ? hfuzz->pid : fuzzer->pid;
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000241 pid_t childPid = fuzzer->pid;
242
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000243 timer_t timerid;
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000244 if (arch_setTimer(&timerid) == false) {
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000245 LOGMSG(l_FATAL, "Couldn't set timer");
246 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000247
robert.swiecki@gmail.com10e69b62015-03-08 02:21:56 +0000248 int perfFd[3];
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000249
Jaggerdfe815f2015-06-29 01:59:06 +0200250 for (;;) {
251 int status;
252 pid_t pid = wait4(childPid, &status, __WNOTHREAD | __WALL | WUNTRACED, NULL);
253 if (pid == -1 && errno == EINTR) {
254 continue;
255 }
256 if (pid != childPid) {
257 LOGMSG_P(l_FATAL, "wait4()=%d =! %d", pid, childPid);
258 }
Jaggerc85fd6e2015-06-29 02:02:04 +0200259 if (WIFSTOPPED(status)) {
260 break;
Jaggerdfe815f2015-06-29 01:59:06 +0200261 }
Jaggerc85fd6e2015-06-29 02:02:04 +0200262 LOGMSG_P(l_FATAL, "PID '%d' is not in a stopped state", pid);
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000263 }
robert.swiecki@gmail.com6a623cd2015-04-02 00:16:28 +0000264 if (arch_ptraceAttach(ptracePid) == false) {
robert.swiecki@gmail.com72e5c432015-04-02 01:27:31 +0000265 LOGMSG(l_FATAL, "Couldn't attach to pid %d", ptracePid);
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000266 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000267 if (arch_perfEnable(ptracePid, hfuzz, perfFd) == false) {
robert.swiecki@gmail.com72e5c432015-04-02 01:27:31 +0000268 LOGMSG(l_FATAL, "Couldn't enable perf counters for pid %d", ptracePid);
robert.swiecki@gmail.com627c1932015-02-25 02:35:00 +0000269 }
robert.swiecki@gmail.comb52d92b2015-04-02 02:28:06 +0000270 kill(childPid, SIGCONT);
robert.swiecki@gmail.comd7818972015-02-24 23:37:59 +0000271
272 for (;;) {
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000273 int status;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300274
275 // wait3 syscall is no longer present in Android
276#if !defined(__ANDROID__)
robert.swiecki24dafd52015-03-20 17:46:34 +0000277 pid_t pid = wait3(&status, __WNOTHREAD | __WALL, NULL);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300278#else
279 pid_t pid = wait4(-1, &status, __WNOTHREAD | __WALL, NULL);
280#endif
robert.swiecki@gmail.com6e3d04c2015-02-25 02:04:15 +0000281
robert.swiecki24dafd52015-03-20 17:46:34 +0000282 LOGMSG_P(l_DEBUG, "PID '%d' returned with status '%d'", pid, status);
robert.swiecki@gmail.comd7818972015-02-24 23:37:59 +0000283
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000284 if (pid == -1 && errno == EINTR) {
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000285 arch_checkTimeLimit(hfuzz, fuzzer);
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000286 continue;
287 }
288 if (pid == -1 && errno == ECHILD) {
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000289 LOGMSG(l_DEBUG, "No more processes to track");
robert.swiecki@gmail.com8a50da42015-03-28 00:56:56 +0000290 break;
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000291 }
292 if (pid == -1) {
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300293#if !defined(__ANDROID__)
294 LOGMSG_P(l_FATAL, "wait3() failed");
295#else
296 LOGMSG_P(l_FATAL, "wait4() failed");
297#endif
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000298 }
299
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000300 uint64_t tmp;
301 if ((tmp = arch_ptraceGetCustomPerf(hfuzz, ptracePid)) != 0ULL) {
302 fuzzer->branchCnt[3] = tmp;
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000303 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000304
305 if (ptracePid == childPid) {
306 arch_ptraceAnalyze(hfuzz, status, pid, fuzzer);
307 continue;
308 }
robert.swiecki@gmail.com57573b82015-04-02 00:26:35 +0000309 if (pid == childPid && (WIFEXITED(status) || WIFSIGNALED(status))) {
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000310 break;
311 }
312 if (pid == childPid) {
313 continue;
314 }
315
316 arch_ptraceAnalyze(hfuzz, status, pid, fuzzer);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000317 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000318 arch_removeTimer(&timerid);
Jagger4e5b59b2015-06-29 02:08:48 +0200319 arch_perfAnalyze(hfuzz, fuzzer, perfFd);
robert.swiecki@gmail.com8a50da42015-03-28 00:56:56 +0000320 return;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000321}
322
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000323bool arch_archInit(honggfuzz_t * hfuzz)
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000324{
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000325 return true;
326 if (hfuzz) {
327 return true;
328 }
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000329}