blob: 199e54e2fcd18eae83074e618521de68a4995252 [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
robert.swiecki3da0ea52015-03-12 14:19:45 +0000136 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs) && hfuzz->envs[i]; i++) {
137 putenv(hfuzz->envs[i]);
138 }
139
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000140 if (hfuzz->nullifyStdio) {
141 util_nullifyStdio();
142 }
143
144 if (hfuzz->fuzzStdin) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000145 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000146 * Uglyyyyyy ;)
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000147 */
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000148 if (!util_redirectStdin(fileName)) {
149 return false;
150 }
151 }
robert.swiecki3da0ea52015-03-12 14:19:45 +0000152 /*
153 * Wait for the ptrace to attach
154 */
robert.swiecki@gmail.com59ca7eb2015-04-02 02:25:22 +0000155 syscall(__NR_tkill, syscall(__NR_gettid), SIGSTOP);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000156 execvp(args[0], args);
157
158 util_recoverStdio();
159 LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
160 return false;
161}
162
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000163static void arch_sigFunc(int signo, siginfo_t * si, void *dummy)
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000164{
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000165 if (signo != SIGALRM) {
166 LOGMSG(l_ERROR, "Signal != SIGALRM (%d)", signo);
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000167 }
168 return;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000169 if (si == NULL) {
170 return;
171 }
172 if (dummy == NULL) {
173 return;
174 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000175}
176
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000177static void arch_removeTimer(timer_t * timerid)
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000178{
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000179 timer_delete(*timerid);
180}
181
182static bool arch_setTimer(timer_t * timerid)
183{
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000184 struct sigevent sevp = {
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000185 .sigev_value.sival_ptr = timerid,
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000186 .sigev_signo = SIGALRM,
187 .sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL,
188 ._sigev_un._tid = syscall(__NR_gettid),
189 };
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000190 if (timer_create(CLOCK_REALTIME, &sevp, timerid) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000191 LOGMSG_P(l_ERROR, "timer_create(CLOCK_REALTIME) failed");
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000192 return false;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000193 }
194 /*
195 * Kick in every 200ms, starting with the next second
196 */
197 const struct itimerspec ts = {
198 .it_value = {.tv_sec = 1,.tv_nsec = 0},
199 .it_interval = {.tv_sec = 0,.tv_nsec = 200000000,},
200 };
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000201 if (timer_settime(*timerid, 0, &ts, NULL) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000202 LOGMSG_P(l_ERROR, "timer_settime() failed");
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000203 timer_delete(*timerid);
204 return false;
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000205 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000206 sigset_t smask;
207 sigemptyset(&smask);
208 struct sigaction sa = {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000209 .sa_handler = NULL,
210 .sa_sigaction = arch_sigFunc,
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000211 .sa_mask = smask,
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000212 .sa_flags = SA_SIGINFO,
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000213 .sa_restorer = NULL,
214 };
215 if (sigaction(SIGALRM, &sa, NULL) == -1) {
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000216 LOGMSG_P(l_ERROR, "sigaciton(SIGALRM) failed");
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000217 return false;
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000218 }
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000219
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000220 return true;
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000221}
222
223static void arch_checkTimeLimit(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
224{
robert.swiecki@gmail.com3213a112015-03-12 01:42:02 +0000225 int64_t curMillis = util_timeNowMillis();
226 int64_t diffMillis = curMillis - fuzzer->timeStartedMillis;
227 if (diffMillis > (hfuzz->tmOut * 1000)) {
228 LOGMSG(l_WARN, "PID %d took too much time (limit %ld s). Sending SIGKILL",
229 fuzzer->pid, hfuzz->tmOut);
robert.swiecki@gmail.com1111d132015-03-12 01:32:26 +0000230 kill(fuzzer->pid, SIGKILL);
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000231 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000232}
233
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000234void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
235{
robert.swiecki@gmail.com57573b82015-04-02 00:26:35 +0000236 pid_t ptracePid = (hfuzz->pid > 0) ? hfuzz->pid : fuzzer->pid;
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000237 pid_t childPid = fuzzer->pid;
238
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000239 timer_t timerid;
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000240 if (arch_setTimer(&timerid) == false) {
robert.swiecki@gmail.comeb904302015-03-12 04:50:58 +0000241 LOGMSG(l_FATAL, "Couldn't set timer");
242 }
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000243
robert.swiecki@gmail.com10e69b62015-03-08 02:21:56 +0000244 int perfFd[3];
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000245
246 int status;
robert.swiecki@gmail.com59ca7eb2015-04-02 02:25:22 +0000247 pid_t pid = wait4(childPid, &status, __WNOTHREAD | __WALL | WUNTRACED, NULL);
248 if (pid != childPid) {
249 LOGMSG(l_FATAL, "wait4() =! pid (%d)", childPid);
250 }
251 if (!WIFSTOPPED(status)) {
252 LOGMSG(l_FATAL, "PID '%d' is not in a stopped state", pid);
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000253 }
robert.swiecki@gmail.com6a623cd2015-04-02 00:16:28 +0000254 if (arch_ptraceAttach(ptracePid) == false) {
robert.swiecki@gmail.com72e5c432015-04-02 01:27:31 +0000255 LOGMSG(l_FATAL, "Couldn't attach to pid %d", ptracePid);
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000256 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000257 if (arch_perfEnable(ptracePid, hfuzz, perfFd) == false) {
robert.swiecki@gmail.com72e5c432015-04-02 01:27:31 +0000258 LOGMSG(l_FATAL, "Couldn't enable perf counters for pid %d", ptracePid);
robert.swiecki@gmail.com627c1932015-02-25 02:35:00 +0000259 }
robert.swiecki@gmail.com59ca7eb2015-04-02 02:25:22 +0000260 if (childPid != ptracePid) {
261 kill(childPid, SIGCONT);
262 }
robert.swiecki@gmail.comd7818972015-02-24 23:37:59 +0000263
264 for (;;) {
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000265 int status;
robert.swiecki24dafd52015-03-20 17:46:34 +0000266 pid_t pid = wait3(&status, __WNOTHREAD | __WALL, NULL);
robert.swiecki@gmail.com6e3d04c2015-02-25 02:04:15 +0000267
robert.swiecki24dafd52015-03-20 17:46:34 +0000268 LOGMSG_P(l_DEBUG, "PID '%d' returned with status '%d'", pid, status);
robert.swiecki@gmail.comd7818972015-02-24 23:37:59 +0000269
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000270 if (pid == -1 && errno == EINTR) {
robert.swiecki@gmail.comdbcc7a32015-03-12 00:22:20 +0000271 arch_checkTimeLimit(hfuzz, fuzzer);
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000272 continue;
273 }
274 if (pid == -1 && errno == ECHILD) {
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000275 arch_perfAnalyze(hfuzz, fuzzer, perfFd);
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000276 LOGMSG(l_DEBUG, "No more processes to track");
robert.swiecki@gmail.com8a50da42015-03-28 00:56:56 +0000277 break;
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000278 }
279 if (pid == -1) {
280 LOGMSG_P(l_FATAL, "wait3() failed");
robert.swiecki@gmail.com004ddfe2015-02-25 02:57:39 +0000281 }
282
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000283 uint64_t tmp;
284 if ((tmp = arch_ptraceGetCustomPerf(hfuzz, ptracePid)) != 0ULL) {
285 fuzzer->branchCnt[3] = tmp;
robert.swiecki@gmail.comd526d312015-03-12 02:12:50 +0000286 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000287
288 if (ptracePid == childPid) {
289 arch_ptraceAnalyze(hfuzz, status, pid, fuzzer);
290 continue;
291 }
robert.swiecki@gmail.com57573b82015-04-02 00:26:35 +0000292 if (pid == childPid && (WIFEXITED(status) || WIFSIGNALED(status))) {
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000293 arch_perfAnalyze(hfuzz, fuzzer, perfFd);
294 break;
295 }
296 if (pid == childPid) {
297 continue;
298 }
299
300 arch_ptraceAnalyze(hfuzz, status, pid, fuzzer);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000301 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000302 arch_removeTimer(&timerid);
robert.swiecki@gmail.com8a50da42015-03-28 00:56:56 +0000303 return;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000304}
305
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000306bool arch_archInit(honggfuzz_t * hfuzz)
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000307{
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000308 return true;
309 if (hfuzz) {
310 return true;
311 }
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000312}