blob: a0bf934670dab4a254228d44f2f6c0910277d145 [file] [log] [blame]
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +02001#include "common.h"
2#include "sanitizers.h"
3
4#include <ctype.h>
5#include <dirent.h>
6#include <inttypes.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/mman.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13
14#include "files.h"
15#include "log.h"
16#include "util.h"
17
18/* Stringify */
19#define XSTR(x) #x
20#define STR(x) XSTR(x)
21
22/*
23 * All clang sanitizers except ASan can be activated for target binaries
24 * with or without the matching runtime libraries (libcompiler_rt). If runtime
25 * libraries are included in target fuzzing environment, we can benefit from the
26 * various Die() callbacks and abort/exit logic manipulation. However, some
27 * setups (e.g. Android production ARM/ARM64 devices) enable sanitizers such as
28 * UBSan without the runtime libraries. As such they default ftrap is activated
29 * which is for most cases a SIGABRT. For such cases user needs to enable SIGABRT
30 * monitoring flag, otherwise these crashes will be missed.
31 *
32 * Normally SIGABRT is not a monitored signal for Android OS, since it produces
33 * lots of useless crashes due to way Android process termination hacks work. As
34 * a result the sanitizer's 'abort_on_error' flag cannot be utilized since it
35 * invokes abort() internally. In order to not lose crashes a custom exitcode can
36 * be registered and monitored. Since exitcode is a global flag, it's assumed
37 * that target is compiled with only one sanitizer type enabled at a time.
38 *
39 * For cases where clang runtime library linking is not an option SIGABRT should
40 * be monitored even for noise targets, such as the Android OS, since not
41 * alternative exists.
Anestis Bechtsoudis523fccb2016-12-28 12:11:13 +020042 *
43 * There might be cases where ASan instrumented targets crash while generating
44 * reports for detected errors (inside __asan_report_error() proc). Under such
45 * scenarios target fails to exit or SIGABRT (AsanDie() proc) as defined in
46 * ASAN_OPTIONS flags, leaving garbage logs. An attempt is made to parse such
47 * logs for cases where enough data are written to identify potentially missed
48 * crashes. If ASan internal error results into a SIGSEGV being raised, it
49 * will get caught from ptrace API, handling the discovered ASan internal crash.
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +020050 */
51
52/* 'log_path' output directory for sanitizer reports */
53#define kSANLOGDIR "log_path="
54
55/* 'coverage_dir' output directory for coverage data files is set dynamically */
56#define kSANCOVDIR "coverage_dir="
57
58/* Raise SIGABRT on error or continue with exitcode logic */
59#define kABORT_ENABLED "abort_on_error=1"
60#define kABORT_DISABLED "abort_on_error=0"
61
62/*
63 * Common sanitizer flags
64 *
65 * symbolize: Disable symbolication since it changes logs (which are parsed) format
66 */
67#define kSAN_COMMON "symbolize=0"
68
69/* --{ ASan }-- */
70/*
71 *Sanitizer specific flags (notice that if enabled 'abort_on_error' has priority
72 * over exitcode')
73 */
74#define kASAN_COMMON_OPTS "allow_user_segv_handler=1:"\
75 "handle_segv=0:"\
76 "allocator_may_return_null=1:"\
Anestis Bechtsoudis9ea67cb2016-12-28 12:38:23 +020077 kSAN_COMMON":exitcode=" STR(HF_SAN_EXIT_CODE)
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +020078/* Platform specific flags */
79#if defined(__ANDROID__)
80/*
81 * start_deactivated: Enable on Android to reduce memory usage (useful when not all
82 * target's DSOs are compiled with sanitizer enabled
83 */
84#define kASAN_OPTS kASAN_COMMON_OPTS":start_deactivated=1"
85#else
86#define kASAN_OPTS kASAN_COMMON_OPTS
87#endif
88
89/* --{ UBSan }-- */
Anestis Bechtsoudis9ea67cb2016-12-28 12:38:23 +020090#define kUBSAN_OPTS kSAN_COMMON":exitcode=" STR(HF_SAN_EXIT_CODE)
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +020091
92/* --{ MSan }-- */
Anestis Bechtsoudis9ea67cb2016-12-28 12:38:23 +020093#define kMSAN_OPTS kSAN_COMMON":exit_code=" STR(HF_SAN_EXIT_CODE) ":"\
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +020094 "wrap_signals=0:print_stats=1"
95
96/*
97 * If the program ends with a signal that ASan does not handle (or can not
98 * handle at all, like SIGKILL), coverage data will be lost. This is a big
99 * problem on Android, where SIGKILL is a normal way of evicting applications
100 * from memory. With 'coverage_direct=1' coverage data is written to a
101 * memory-mapped file as soon as it collected. Non-Android targets can disable
102 * coverage direct when more coverage data collection methods are implemented.
103 */
104#define kSAN_COV_OPTS "coverage=1:coverage_direct=1"
105
106bool sanitizers_Init(honggfuzz_t * hfuzz)
107{
108 if (hfuzz->linux.pid > 0 || hfuzz->enableSanitizers == false) {
109 return true;
110 }
111
112 /* Set sanitizer flags once to avoid performance overhead per worker spawn */
113 size_t flagsSz = 0;
114
115 /* Larger constant combination + 2 dynamic paths */
116 size_t bufSz =
117 sizeof(kASAN_OPTS) + 1 + sizeof(kABORT_ENABLED) + 1 + sizeof(kSANLOGDIR) + PATH_MAX + 1 +
118 sizeof(kSANCOVDIR) + PATH_MAX + 1;
119 char *san_opts = util_Calloc(bufSz);
120 defer {
121 free(san_opts);
122 };
123
124 char *abortFlag;
125 if (hfuzz->monitorSIGABRT) {
126 abortFlag = kABORT_ENABLED;
127 } else {
128 abortFlag = kABORT_DISABLED;
129 }
130
Anestis Bechtsoudis523fccb2016-12-28 12:11:13 +0200131 /* Address Sanitizer (ASan) */
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200132 if (hfuzz->useSanCov) {
133 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s:%s%s/%s", kASAN_OPTS, abortFlag, kSAN_COV_OPTS,
134 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
135 kLOGPREFIX);
136 } else {
137 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kASAN_OPTS, abortFlag, kSANLOGDIR,
138 hfuzz->workDir, kLOGPREFIX);
139 }
140
141 flagsSz = strlen(san_opts) + 1;
142 hfuzz->sanOpts.asanOpts = util_Calloc(flagsSz);
143 memcpy(hfuzz->sanOpts.asanOpts, san_opts, flagsSz);
144 LOG_D("ASAN_OPTIONS=%s", hfuzz->sanOpts.asanOpts);
145
Anestis Bechtsoudis523fccb2016-12-28 12:11:13 +0200146 /* Undefined Behavior Sanitizer (UBSan) */
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200147 memset(san_opts, 0, bufSz);
148 if (hfuzz->useSanCov) {
149 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s:%s%s/%s", kUBSAN_OPTS, abortFlag, kSAN_COV_OPTS,
150 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
151 kLOGPREFIX);
152 } else {
153 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kUBSAN_OPTS, abortFlag, kSANLOGDIR,
154 hfuzz->workDir, kLOGPREFIX);
155 }
156
157 flagsSz = strlen(san_opts) + 1;
158 hfuzz->sanOpts.ubsanOpts = util_Calloc(flagsSz);
159 memcpy(hfuzz->sanOpts.ubsanOpts, san_opts, flagsSz);
160 LOG_D("UBSAN_OPTIONS=%s", hfuzz->sanOpts.ubsanOpts);
161
Anestis Bechtsoudis523fccb2016-12-28 12:11:13 +0200162 /* Memory Sanitizer (MSan) */
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200163 memset(san_opts, 0, bufSz);
164 const char *msan_reports_flag = "report_umrs=0";
165 if (hfuzz->msanReportUMRS) {
166 msan_reports_flag = "report_umrs=1";
167 }
168
169 if (hfuzz->useSanCov) {
170 snprintf(san_opts, bufSz, "%s:%s:%s:%s:%s%s/%s:%s%s/%s", kMSAN_OPTS, abortFlag,
171 msan_reports_flag, kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR,
172 kSANLOGDIR, hfuzz->workDir, kLOGPREFIX);
173 } else {
174 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s", kMSAN_OPTS, abortFlag, msan_reports_flag,
175 kSANLOGDIR, hfuzz->workDir, kLOGPREFIX);
176 }
177
178 flagsSz = strlen(san_opts) + 1;
179 hfuzz->sanOpts.msanOpts = util_Calloc(flagsSz);
180 memcpy(hfuzz->sanOpts.msanOpts, san_opts, flagsSz);
181 LOG_D("MSAN_OPTIONS=%s", hfuzz->sanOpts.msanOpts);
182
183 return true;
184}
185
186bool sanitizers_prepareExecve(honggfuzz_t * hfuzz)
187{
188 if (hfuzz->enableSanitizers == false) {
189 return true;
190 }
191
192 /* Address Sanitizer (ASan) */
193 if (hfuzz->sanOpts.asanOpts) {
194 if (setenv("ASAN_OPTIONS", hfuzz->sanOpts.asanOpts, 1) == -1) {
195 PLOG_E("setenv(ASAN_OPTIONS) failed");
196 return false;
197 }
198 }
199
200 /* Memory Sanitizer (MSan) */
201 if (hfuzz->sanOpts.msanOpts) {
202 if (setenv("MSAN_OPTIONS", hfuzz->sanOpts.msanOpts, 1) == -1) {
203 PLOG_E("setenv(MSAN_OPTIONS) failed");
204 return false;
205 }
206 }
207
208 /* Undefined Behavior Sanitizer (UBSan) */
209 if (hfuzz->sanOpts.ubsanOpts) {
210 if (setenv("UBSAN_OPTIONS", hfuzz->sanOpts.ubsanOpts, 1) == -1) {
211 PLOG_E("setenv(UBSAN_OPTIONS) failed");
212 return false;
213 }
214 }
215
216 return true;
217}