1 #include "sanitizers.h"
2
3 #include <ctype.h>
4 #include <dirent.h>
5 #include <inttypes.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/mman.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12
13 #include "cmdline.h"
14 #include "libhfcommon/common.h"
15 #include "libhfcommon/files.h"
16 #include "libhfcommon/log.h"
17 #include "libhfcommon/util.h"
18
19 /*
20 * All clang sanitizers, except ASan, can be activated for target binaries
21 * with or without the matching runtime library (libcompiler_rt). If runtime
22 * libraries are included in target fuzzing environment, we can benefit from the
23 * various Die() callbacks and abort/exit logic manipulation. However, some
24 * setups (e.g. Android production ARM/ARM64 devices) enable sanitizers, such as
25 * UBSan, without the runtime libraries. As such, their default ftrap is activated
26 * which is for most cases a SIGABRT. For these cases end-user needs to enable
27 * SIGABRT monitoring flag, otherwise these crashes will be missed.
28 *
29 * Normally SIGABRT is not a wanted signal to monitor for Android, since it produces
30 * lots of useless crashes due to way Android process termination hacks work. As
31 * a result the sanitizer's 'abort_on_error' flag cannot be utilized since it
32 * invokes abort() internally. In order to not lose crashes a custom exitcode can
33 * be registered and monitored. Since exitcode is a global flag, it's assumed
34 * that target is compiled with only one sanitizer type enabled at a time.
35 *
36 * For cases where clang runtime library linking is not an option, SIGABRT should
37 * be monitored even for noisy targets, such as the Android OS, since no viable
38 * alternative exists.
39 *
40 * There might be cases where ASan instrumented targets crash while generating
41 * reports for detected errors (inside __asan_report_error() proc). Under such
42 * scenarios target fails to exit or SIGABRT (AsanDie() proc) as defined in
43 * ASAN_OPTIONS flags, leaving garbage logs. An attempt is made to parse such
44 * logs for cases where enough data are written to identify potentially missed
45 * crashes. If ASan internal error results into a SIGSEGV being raised, it
46 * will get caught from ptrace API, handling the discovered ASan internal crash.
47 */
48
49 /* 'log_path' output directory for sanitizer reports */
50 #define kSANLOGDIR "log_path="
51
52 /* Raise SIGABRT on error or continue with exitcode logic */
53 #define kABORT_ENABLED "abort_on_error=1"
54 #define kABORT_DISABLED "abort_on_error=0"
55
56 /*
57 * Common sanitizer flags
58 *
59 * symbolize: Disable symbolication since it changes logs (which are parsed) format
60 */
61 #define kSAN_COMMON "symbolize=0"
62
63 /* --{ ASan }-- */
64 /*
65 *Sanitizer specific flags (notice that if enabled 'abort_on_error' has priority
66 * over exitcode')
67 */
68 #define kASAN_COMMON_OPTS \
69 "allow_user_segv_handler=1:" \
70 "handle_segv=0:" \
71 "allocator_may_return_null=1:" kSAN_COMMON ":exitcode=" HF_XSTR(HF_SAN_EXIT_CODE)
72 /* Platform specific flags */
73 #if defined(__ANDROID__)
74 /*
75 * start_deactivated: Enable on Android to reduce memory usage (useful when not all
76 * target's DSOs are compiled with sanitizer enabled
77 */
78 #define kASAN_OPTS kASAN_COMMON_OPTS ":start_deactivated=1"
79 #else
80 #define kASAN_OPTS kASAN_COMMON_OPTS
81 #endif
82
83 /* --{ UBSan }-- */
84 #define kUBSAN_OPTS kSAN_COMMON ":exitcode=" STR(HF_SAN_EXIT_CODE)
85
86 /* --{ MSan }-- */
87 #define kMSAN_OPTS \
88 kSAN_COMMON ":exit_code=" STR(HF_SAN_EXIT_CODE) ":" \
89 "wrap_signals=0:print_stats=1"
90
91 /* If no sanitzer support was requested, simply make it use abort() on errors */
92 #define kSAN_REGULAR \
93 "abort_on_error=1:handle_segv=0:handle_sigbus=0:handle_abort=0:" \
94 "handle_sigill=0:handle_sigfpe=0:allocator_may_return_null=1:" \
95 "symbolize=1:detect_leaks=0:disable_coredump=0:" \
96 "detect_odr_violation=0"
97
98 /*
99 * If the program ends with a signal that ASan does not handle (or can not
100 * handle at all, like SIGKILL), coverage data will be lost. This is a big
101 * problem on Android, where SIGKILL is a normal way of evicting applications
102 * from memory. With 'coverage_direct=1' coverage data is written to a
103 * memory-mapped file as soon as it collected. Non-Android targets can disable
104 * coverage direct when more coverage data collection methods are implemented.
105 */
106 #define kSAN_COV_OPTS "coverage=1:coverage_direct=1"
107
sanitizers_AddFlag(honggfuzz_t * hfuzz,const char * env,char * buf,size_t buflen)108 static void sanitizers_AddFlag(honggfuzz_t* hfuzz, const char* env, char* buf, size_t buflen) {
109 const char* abortFlag = hfuzz->cfg.monitorSIGABRT ? kABORT_ENABLED : kABORT_DISABLED;
110 if (getenv(env)) {
111 LOG_W("The '%s' envar is already set. Not overriding it!", env);
112 return;
113 }
114
115 if (!hfuzz->sanitizer.enable) {
116 snprintf(buf, buflen, "%s=%s", env, kSAN_REGULAR);
117 } else {
118 snprintf(buf, buflen, "%s=%s:%s:%s%s/%s", env, kASAN_OPTS, abortFlag, kSANLOGDIR,
119 hfuzz->io.workDir, kLOGPREFIX);
120 }
121 /*
122 * It will make ASAN to start background thread to check RSS mem use, which
123 * will prevent the NetDrvier from using unshare(CLONE_NEWNET), which cannot
124 * be used in multi-threaded contexts
125 */
126 if (!hfuzz->exe.netDriver && hfuzz->exe.rssLimit) {
127 util_ssnprintf(buf, buflen, ":soft_rss_limit_mb=%" PRId64, hfuzz->exe.rssLimit);
128 }
129
130 cmdlineAddEnv(hfuzz, buf);
131 LOG_D("%s", env);
132 }
133
sanitizers_Init(honggfuzz_t * hfuzz)134 bool sanitizers_Init(honggfuzz_t* hfuzz) {
135 static char asanOpts[4096];
136 sanitizers_AddFlag(hfuzz, "ASAN_OPTIONS", asanOpts, sizeof(asanOpts));
137 static char ubsanOpts[4096];
138 sanitizers_AddFlag(hfuzz, "UBSAN_OPTIONS", ubsanOpts, sizeof(ubsanOpts));
139 static char msanOpts[4096];
140 sanitizers_AddFlag(hfuzz, "MSAN_OPTIONS", msanOpts, sizeof(msanOpts));
141 static char lsanOpts[4096];
142 sanitizers_AddFlag(hfuzz, "LSAN_OPTIONS", lsanOpts, sizeof(lsanOpts));
143
144 return true;
145 }
146