1 /*
2 *
3 * honggfuzz - architecture dependent code (POSIX / SIGNAL)
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 "arch.h"
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/cdefs.h>
34 #include <sys/resource.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <time.h>
39 #include <unistd.h>
40
41 #include "log.h"
42 #include "files.h"
43 #include "util.h"
44 #include "sancov.h"
45
46 #ifdef __ANDROID__
47 #ifndef WIFCONTINUED
48 #define WIFCONTINUED(x) WEXITSTATUS(0)
49 #endif
50 #endif
51
52 /* *INDENT-OFF* */
53 struct {
54 bool important;
55 const char *descr;
56 } arch_sigs[NSIG] = {
57 [0 ... (NSIG - 1)].important = false,
58 [0 ... (NSIG - 1)].descr = "UNKNOWN",
59
60 [SIGILL].important = true,
61 [SIGILL].descr = "SIGILL",
62 [SIGFPE].important = true,
63 [SIGFPE].descr = "SIGFPE",
64 [SIGSEGV].important = true,
65 [SIGSEGV].descr = "SIGSEGV",
66 [SIGBUS].important = true,
67 [SIGBUS].descr = "SIGBUS",
68 [SIGABRT].important = true,
69 [SIGABRT].descr = "SIGABRT"
70 };
71 /* *INDENT-ON* */
72
73 /*
74 * Returns true if a process exited (so, presumably, we can delete an input
75 * file)
76 */
arch_analyzeSignal(honggfuzz_t * hfuzz,int status,fuzzer_t * fuzzer)77 static bool arch_analyzeSignal(honggfuzz_t * hfuzz, int status, fuzzer_t * fuzzer)
78 {
79 /*
80 * Resumed by delivery of SIGCONT
81 */
82 if (WIFCONTINUED(status)) {
83 return false;
84 }
85
86 if (WIFEXITED(status) || WIFSIGNALED(status)) {
87 sancov_Analyze(hfuzz, fuzzer);
88 }
89
90 /*
91 * Boring, the process just exited
92 */
93 if (WIFEXITED(status)) {
94 LOG_D("Process (pid %d) exited normally with status %d", fuzzer->pid, WEXITSTATUS(status));
95 return true;
96 }
97
98 /*
99 * Shouldn't really happen, but, well..
100 */
101 if (!WIFSIGNALED(status)) {
102 LOG_E("Process (pid %d) exited with the following status %d, please report that as a bug",
103 fuzzer->pid, status);
104 return true;
105 }
106
107 int termsig = WTERMSIG(status);
108 LOG_D("Process (pid %d) killed by signal %d '%s'", fuzzer->pid, termsig, strsignal(termsig));
109 if (!arch_sigs[termsig].important) {
110 LOG_D("It's not that important signal, skipping");
111 return true;
112 }
113
114 char localtmstr[PATH_MAX];
115 util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
116
117 char newname[PATH_MAX];
118
119 /* If dry run mode, copy file with same name into workspace */
120 if (hfuzz->origFlipRate == 0.0L && hfuzz->useVerifier) {
121 snprintf(newname, sizeof(newname), "%s", fuzzer->origFileName);
122 } else {
123 snprintf(newname, sizeof(newname), "%s/%s.%d.%s.%s.%s",
124 hfuzz->workDir, arch_sigs[termsig].descr, fuzzer->pid, localtmstr,
125 fuzzer->origFileName, hfuzz->fileExtn);
126 }
127
128 LOG_I("Ok, that's interesting, saving the '%s' as '%s'", fuzzer->fileName, newname);
129
130 /*
131 * All crashes are marked as unique due to lack of information in POSIX arch
132 */
133 __sync_fetch_and_add(&hfuzz->crashesCnt, 1UL);
134 __sync_fetch_and_add(&hfuzz->uniqueCrashesCnt, 1UL);
135
136 if (files_copyFile(fuzzer->fileName, newname, NULL) == false) {
137 LOG_E("Couldn't save '%s' as '%s'", fuzzer->fileName, newname);
138 }
139 return true;
140 }
141
arch_fork(honggfuzz_t * hfuzz UNUSED)142 pid_t arch_fork(honggfuzz_t * hfuzz UNUSED)
143 {
144 return fork();
145 }
146
arch_launchChild(honggfuzz_t * hfuzz,char * fileName)147 bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
148 {
149 #define ARGS_MAX 512
150 char *args[ARGS_MAX + 2];
151 char argData[PATH_MAX] = { 0 };
152 int x;
153
154 for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
155 if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
156 args[x] = fileName;
157 } else if (!hfuzz->fuzzStdin && strstr(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER)) {
158 const char *off = strstr(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER);
159 snprintf(argData, PATH_MAX, "%.*s%s", (int)(off - hfuzz->cmdline[x]), hfuzz->cmdline[x],
160 fileName);
161 args[x] = argData;
162 } else {
163 args[x] = hfuzz->cmdline[x];
164 }
165 }
166
167 args[x++] = NULL;
168
169 LOG_D("Launching '%s' on file '%s'", args[0], fileName);
170
171 execvp(args[0], args);
172 return false;
173 }
174
arch_reapChild(honggfuzz_t * hfuzz,fuzzer_t * fuzzer)175 void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
176 {
177 int status;
178
179 for (;;) {
180 #ifndef __WALL
181 #define __WALL 0
182 #endif
183 while (wait4(fuzzer->pid, &status, __WALL, NULL) != fuzzer->pid) ;
184 LOG_D("Process (pid %d) came back with status %d", fuzzer->pid, status);
185
186 if (arch_analyzeSignal(hfuzz, status, fuzzer)) {
187 return;
188 }
189 }
190 }
191
arch_archInit(honggfuzz_t * hfuzz UNUSED)192 bool arch_archInit(honggfuzz_t * hfuzz UNUSED)
193 {
194 return true;
195 }
196