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