1 #include "instrument.h"
2 
3 #include <ctype.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <inttypes.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 
17 #include "honggfuzz.h"
18 #include "libhfcommon/common.h"
19 #include "libhfcommon/log.h"
20 #include "libhfcommon/util.h"
21 
22 __attribute__((visibility("default"))) __attribute__((used))
23 const char* const LIBHFUZZ_module_instrument = "LIBHFUZZ_module_instrument";
24 
25 /*
26  * We require SSE4.2 with x86-(32|64) for the 'popcnt', as it's much faster than the software
27  * emulation of gcc/clang
28  */
29 #if defined(__x86_64__) || defined(__i386__)
30 #define ATTRIBUTE_X86_REQUIRE_SSE42 __attribute__((__target__("sse4.2")))
31 #else
32 #define ATTRIBUTE_X86_REQUIRE_SSE42
33 #endif /* defined(__x86_64__) || defined(__i386__) */
34 
35 /*
36  * If there's no _HF_BITMAP_FD available (running without the honggfuzz
37  * supervisor), use a dummy bitmap and control structure located in the BSS
38  */
39 static feedback_t bbMapFb;
40 feedback_t* feedback = &bbMapFb;
41 uint32_t my_thread_no = 0;
42 
initializeInstrument(void)43 __attribute__((constructor)) static void initializeInstrument(void) {
44     if (fcntl(_HF_LOG_FD, F_GETFD) != -1) {
45         enum llevel_t ll = INFO;
46         const char* llstr = getenv(_HF_LOG_LEVEL_ENV);
47         if (llstr) {
48             ll = atoi(llstr);
49         }
50         logInitLogFile(NULL, _HF_LOG_FD, ll);
51     }
52 
53     char* my_thread_no_str = getenv(_HF_THREAD_NO_ENV);
54     if (my_thread_no_str == NULL) {
55         LOG_D("The '%s' envvar is not set", _HF_THREAD_NO_ENV);
56         return;
57     }
58     my_thread_no = atoi(my_thread_no_str);
59 
60     if (my_thread_no >= _HF_THREAD_MAX) {
61         LOG_F("Received (via envvar) my_thread_no > _HF_THREAD_MAX (%" PRIu32 " > %d)\n",
62             my_thread_no, _HF_THREAD_MAX);
63     }
64 
65     struct stat st;
66     if (fstat(_HF_BITMAP_FD, &st) == -1) {
67         return;
68     }
69     if (st.st_size != sizeof(feedback_t)) {
70         LOG_F(
71             "size of the feedback structure mismatch: st.size != sizeof(feedback_t) (%zu != %zu). "
72             "Link your fuzzed binaries with the newest honggfuzz sources via hfuzz-clang(++)",
73             (size_t)st.st_size, sizeof(feedback_t));
74     }
75     if ((feedback = mmap(NULL, sizeof(feedback_t), PROT_READ | PROT_WRITE, MAP_SHARED,
76              _HF_BITMAP_FD, 0)) == MAP_FAILED) {
77         PLOG_F("mmap(fd=%d, size=%zu) of the feedback structure failed", _HF_BITMAP_FD,
78             sizeof(feedback_t));
79     }
80 
81     /* Reset coverage counters to their initial state */
82     instrumentClearNewCov();
83 }
84 
85 /* Reset the counters of newly discovered edges/pcs/features */
instrumentClearNewCov()86 void instrumentClearNewCov() {
87     feedback->pidFeedbackPc[my_thread_no] = 0U;
88     feedback->pidFeedbackEdge[my_thread_no] = 0U;
89     feedback->pidFeedbackCmp[my_thread_no] = 0U;
90 }
91 
92 /*
93  * -finstrument-functions
94  */
__cyg_profile_func_enter(void * func,void * caller)95 ATTRIBUTE_X86_REQUIRE_SSE42 void __cyg_profile_func_enter(void* func, void* caller) {
96     register size_t pos =
97         (((uintptr_t)func << 12) | ((uintptr_t)caller & 0xFFF)) & _HF_PERF_BITMAP_BITSZ_MASK;
98     register uint8_t prev = ATOMIC_BTS(feedback->bbMapPc, pos);
99     if (!prev) {
100         ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackPc[my_thread_no]);
101     }
102 }
103 
__cyg_profile_func_exit(void * func HF_ATTR_UNUSED,void * caller HF_ATTR_UNUSED)104 ATTRIBUTE_X86_REQUIRE_SSE42 void __cyg_profile_func_exit(
105     void* func HF_ATTR_UNUSED, void* caller HF_ATTR_UNUSED) {
106     return;
107 }
108 
109 /*
110  * -fsanitize-coverage=trace-pc
111  */
__sanitizer_cov_trace_pc(void)112 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_pc(void) {
113     register uintptr_t ret = (uintptr_t)__builtin_return_address(0) & _HF_PERF_BITMAP_BITSZ_MASK;
114     register uint8_t prev = ATOMIC_BTS(feedback->bbMapPc, ret);
115     if (!prev) {
116         ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackPc[my_thread_no]);
117     }
118 }
119 
120 /*
121  * -fsanitize-coverage=trace-cmp
122  */
__sanitizer_cov_trace_cmp1(uint8_t Arg1,uint8_t Arg2)123 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
124     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
125     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcount(Arg1 ^ Arg2));
126     uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
127     if (prev < v) {
128         ATOMIC_SET(feedback->bbMapCmp[pos], v);
129         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
130     }
131 }
132 
__sanitizer_cov_trace_cmp2(uint16_t Arg1,uint16_t Arg2)133 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
134     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
135     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcount(Arg1 ^ Arg2));
136     uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
137     if (prev < v) {
138         ATOMIC_SET(feedback->bbMapCmp[pos], v);
139         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
140     }
141 }
142 
__sanitizer_cov_trace_cmp4(uint32_t Arg1,uint32_t Arg2)143 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
144     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
145     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcount(Arg1 ^ Arg2));
146     uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
147     if (prev < v) {
148         ATOMIC_SET(feedback->bbMapCmp[pos], v);
149         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
150     }
151 }
152 
__sanitizer_cov_trace_cmp8(uint64_t Arg1,uint64_t Arg2)153 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
154     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
155     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcountll(Arg1 ^ Arg2));
156     uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
157     if (prev < v) {
158         ATOMIC_SET(feedback->bbMapCmp[pos], v);
159         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
160     }
161 }
162 
163 /*
164  * Const versions of trace_cmp, we don't use any special handling for these
165  *
166  * For MacOS, these're weak aliases, as Darwin supports only them
167  */
168 
169 #if defined(_HF_ARCH_DARWIN)
170 #pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1
171 #pragma weak __sanitizer_cov_trace_const_cmp2 = __sanitizer_cov_trace_cmp2
172 #pragma weak __sanitizer_cov_trace_const_cmp4 = __sanitizer_cov_trace_cmp4
173 #pragma weak __sanitizer_cov_trace_const_cmp8 = __sanitizer_cov_trace_cmp8
174 #else
175 void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2)
176     __attribute__((alias("__sanitizer_cov_trace_cmp1")));
177 void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2)
178     __attribute__((alias("__sanitizer_cov_trace_cmp2")));
179 void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2)
180     __attribute__((alias("__sanitizer_cov_trace_cmp4")));
181 void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2)
182     __attribute__((alias("__sanitizer_cov_trace_cmp8")));
183 #endif /* defined(_HF_ARCH_DARWIN) */
184 
185 /*
186  * Cases[0] is number of comparison entries
187  * Cases[1] is length of Val in bits
188  */
__sanitizer_cov_trace_switch(uint64_t Val,uint64_t * Cases)189 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t* Cases) {
190     for (uint64_t i = 0; i < Cases[0]; i++) {
191         uintptr_t pos = ((uintptr_t)__builtin_return_address(0) + i) % _HF_PERF_BITMAP_SIZE_16M;
192         uint8_t v = (uint8_t)Cases[1] - __builtin_popcountll(Val ^ Cases[i + 2]);
193         uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
194         if (prev < v) {
195             ATOMIC_SET(feedback->bbMapCmp[pos], v);
196             ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
197         }
198     }
199 }
200 
201 /*
202  * Old version of __sanitizer_cov_trace_cmp[n]. Remove it at some point
203  */
__sanitizer_cov_trace_cmp(uint64_t SizeAndType,uint64_t Arg1,uint64_t Arg2)204 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmp(
205     uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2) {
206     uint64_t CmpSize = (SizeAndType >> 32) / 8;
207     switch (CmpSize) {
208         case (sizeof(uint8_t)):
209             __sanitizer_cov_trace_cmp1(Arg1, Arg2);
210             return;
211         case (sizeof(uint16_t)):
212             __sanitizer_cov_trace_cmp2(Arg1, Arg2);
213             return;
214         case (sizeof(uint32_t)):
215             __sanitizer_cov_trace_cmp4(Arg1, Arg2);
216             return;
217         case (sizeof(uint64_t)):
218             __sanitizer_cov_trace_cmp8(Arg1, Arg2);
219             return;
220     }
221 }
222 
223 /*
224  * gcc-8 -fsanitize-coverage=trace-cmp trace hooks
225  * TODO: evaluate, whether it makes sense to implement them
226  */
__sanitizer_cov_trace_cmpf(float Arg1 HF_ATTR_UNUSED,float Arg2 HF_ATTR_UNUSED)227 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmpf(
228     float Arg1 HF_ATTR_UNUSED, float Arg2 HF_ATTR_UNUSED) {
229 }
__sanitizer_cov_trace_cmpd(double Arg1 HF_ATTR_UNUSED,double Arg2 HF_ATTR_UNUSED)230 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_cmpd(
231     double Arg1 HF_ATTR_UNUSED, double Arg2 HF_ATTR_UNUSED) {
232 }
233 
234 /*
235  * -fsanitize-coverage=trace-div
236  */
__sanitizer_cov_trace_div8(uint64_t Val)237 void __sanitizer_cov_trace_div8(uint64_t Val) {
238     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
239     uint8_t v = ((sizeof(Val) * 8) - __builtin_popcountll(Val));
240     uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
241     if (prev < v) {
242         ATOMIC_SET(feedback->bbMapCmp[pos], v);
243         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
244     }
245 }
246 
__sanitizer_cov_trace_div4(uint32_t Val)247 void __sanitizer_cov_trace_div4(uint32_t Val) {
248     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
249     uint8_t v = ((sizeof(Val) * 8) - __builtin_popcount(Val));
250     uint8_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
251     if (prev < v) {
252         ATOMIC_SET(feedback->bbMapCmp[pos], v);
253         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
254     }
255 }
256 
257 /*
258  * -fsanitize-coverage=indirect-calls
259  */
__sanitizer_cov_trace_pc_indir(uintptr_t callee)260 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_pc_indir(uintptr_t callee) {
261     register size_t pos1 = (uintptr_t)__builtin_return_address(0) << 12;
262     register size_t pos2 = callee & 0xFFF;
263     register size_t pos = (pos1 | pos2) & _HF_PERF_BITMAP_BITSZ_MASK;
264 
265     register uint8_t prev = ATOMIC_BTS(feedback->bbMapPc, pos);
266     if (!prev) {
267         ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackPc[my_thread_no]);
268     }
269 }
270 
271 /*
272  * In LLVM-4.0 it's marked (probably mistakenly) as non-weak symbol, so we need to mark it as weak
273  * here
274  */
__sanitizer_cov_indir_call16(void * callee,void * callee_cache16[]HF_ATTR_UNUSED)275 __attribute__((weak)) ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_indir_call16(
276     void* callee, void* callee_cache16[] HF_ATTR_UNUSED) {
277     register size_t pos1 = (uintptr_t)__builtin_return_address(0) << 12;
278     register size_t pos2 = (uintptr_t)callee & 0xFFF;
279     register size_t pos = (pos1 | pos2) & _HF_PERF_BITMAP_BITSZ_MASK;
280 
281     register uint8_t prev = ATOMIC_BTS(feedback->bbMapPc, pos);
282     if (!prev) {
283         ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackPc[my_thread_no]);
284     }
285 }
286 
287 /*
288  * -fsanitize-coverage=trace-pc-guard
289  */
290 static bool guards_initialized = false;
__sanitizer_cov_trace_pc_guard_init(uint32_t * start,uint32_t * stop)291 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_pc_guard_init(
292     uint32_t* start, uint32_t* stop) {
293     guards_initialized = true;
294     static uint32_t n = 1U;
295     for (uint32_t* x = start; x < stop; x++, n++) {
296         if (n >= _HF_PC_GUARD_MAX) {
297             LOG_F("This process has too many PC guards:%" PRIu32
298                   " (current module:%tu start:%p stop:%p)\n",
299                 n, ((uintptr_t)stop - (uintptr_t)start) / sizeof(start), start, stop);
300         }
301         /* If the corresponding PC was already hit, map this specific guard as non-interesting (0)
302          */
303         *x = ATOMIC_GET(feedback->pcGuardMap[n]) ? 0U : n;
304     }
305 }
306 
__sanitizer_cov_trace_pc_guard(uint32_t * guard)307 ATTRIBUTE_X86_REQUIRE_SSE42 void __sanitizer_cov_trace_pc_guard(uint32_t* guard) {
308 #if defined(__ANDROID__)
309     // ANDROID: Bionic invokes routines that Honggfuzz wraps, before either
310     //          *SAN or Honggfuzz have initialized.  Check to see if Honggfuzz
311     //          has initialized -- if not, force *SAN to initialize (otherwise
312     //          _strcmp() will crash, as it is *SAN-instrumented).
313     //
314     //          Defer all trace_pc_guard activity until trace_pc_guard_init is
315     //          invoked via sancov.module_ctor in the normal process of things.
316     if (!guards_initialized) {
317         void __asan_init(void) __attribute__((weak));
318         if (__asan_init) {
319             __asan_init();
320         }
321         void __msan_init(void) __attribute__((weak));
322         if (__msan_init) {
323             __msan_init();
324         }
325         void __ubsan_init(void) __attribute__((weak));
326         if (__ubsan_init) {
327             __ubsan_init();
328         }
329         void __tsan_init(void) __attribute__((weak));
330         if (__tsan_init) {
331             __tsan_init();
332         }
333         return;
334     }
335 #endif /* defined(__ANDROID__) */
336     if (*guard == 0U) {
337         return;
338     }
339     bool prev = ATOMIC_XCHG(feedback->pcGuardMap[*guard], true);
340     if (prev == false) {
341         ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackEdge[my_thread_no]);
342     }
343     *guard = 0U;
344 }
345 
instrumentUpdateCmpMap(uintptr_t addr,uint32_t v)346 void instrumentUpdateCmpMap(uintptr_t addr, uint32_t v) {
347     uintptr_t pos = addr % _HF_PERF_BITMAP_SIZE_16M;
348     uint32_t prev = ATOMIC_GET(feedback->bbMapCmp[pos]);
349     if (prev < v) {
350         ATOMIC_SET(feedback->bbMapCmp[pos], v);
351         ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev);
352     }
353 }
354