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