blob: b7c52d0748776cdacc500a612150032f35f8452f [file] [log] [blame]
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +02001/*
2 *
3 * honggfuzz - sanitizer coverage feedback parsing
4 * -----------------------------------------------
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may
7 * not use this file except in compliance with the License. You may obtain
8 * a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 * implied. See the License for the specific language governing
16 * permissions and limitations under the License.
17 *
18 */
19
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020020/*
21 * Clang sanitizer coverage (sancov) data parsing functions. Supported methods:
22 * - raw unified data (preferred method)
23 * - individual data per executable/DSO (not preferred since lots of data lost if instrumented
24 * code exits abnormally or with sanitizer unhandled signal (common in Android OS)
Robert Swiecki72d2bef2016-01-19 14:39:26 +010025 *
26 * For raw-unpack method a global (shared across workers) Trie is created for the chosen
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020027 * initial seed and maintained until seed is replaced. Trie nodes store the loaded (as exposed
28 * from *.sancov.map file) execs/DSOs from target application using the map name as key. Trie node
29 * data struct (trieData_t) maintains information for each instrumented map including a bitmap with
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +020030 * all hit relative BB addresses (realBBAddr - baseAddr to circumvent ASLR). Map's bitmap is updated while
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020031 * new areas on target application are discovered based on absolute elitism implemented at
32 * fuzz_sanCovFeedback().
Robert Swiecki72d2bef2016-01-19 14:39:26 +010033 *
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +020034 * For individual data files a pid (fuzzer's thread or remote process) based filename search is performed
35 * to identify all files belonging to examined execution. This method doesn't implement yet bitmap runtime
36 * data to detect newly discovered areas. It's mainly used so far as a comparison metric for raw-unpack method
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020037 * and stability check for sancov experimental features such as coverage counters:
38 * http://clang.llvm.org/docs/SanitizerCoverage.html
39 */
40
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020041#include "common.h"
42#include "sancov.h"
43
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020044#include <ctype.h>
Jagger00265602016-03-10 02:36:27 +010045#include <dirent.h>
46#include <inttypes.h>
47#include <stdio.h>
48#include <stdlib.h>
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020049#include <string.h>
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020050#include <sys/mman.h>
Jagger00265602016-03-10 02:36:27 +010051#include <sys/stat.h>
52#include <sys/types.h>
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020053
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020054#include "files.h"
55#include "log.h"
Jagger00265602016-03-10 02:36:27 +010056#include "util.h"
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020057
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020058/* sancov files magic values */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +020059#define kMagic32 0xC0BFFFFFFFFFFF32
60#define kMagic64 0xC0BFFFFFFFFFFF64
61
Jagger00265602016-03-10 02:36:27 +010062/* Stringify */
63#define XSTR(x) #x
64#define STR(x) XSTR(x)
65
66/* Common sanitizer flags */
67#if _HF_MONITOR_SIGABRT
68#define ABORT_FLAG "abort_on_error=1"
69#else
70#define ABORT_FLAG "abort_on_error=0"
71#endif
72
73#if defined(__ANDROID__)
74/*
75 * symbolize: Disable symbolication since it changes logs (which are parsed) format
76 * start_deactivated: Enable on Android to reduce memory usage (useful when not all
77 * target's DSOs are compiled with sanitizer enabled
78 * abort_on_error: Disable for platforms where SIGABRT is not monitored
79 */
80#define kSAN_COMMON_ARCH "symbolize=0:"ABORT_FLAG":start_deactivated=1"
81#else
82#define kSAN_COMMON_ARCH "symbolize=0:"ABORT_FLAG
83#endif
84
85/* Sanitizer specific flags (set 'abort_on_error has priority over exitcode') */
86#define kASAN_OPTS "allow_user_segv_handler=1:"\
87 "handle_segv=0:"\
88 "allocator_may_return_null=1:"\
89 kSAN_COMMON_ARCH":exitcode=" STR(HF_ASAN_EXIT_CODE)
90
91#define kUBSAN_OPTS kSAN_COMMON_ARCH":exitcode=" STR(HF_UBSAN_EXIT_CODE)
92
93#define kMSAN_OPTS "exit_code=" STR(HF_MSAN_EXIT_CODE) ":"\
94 "wrap_signals=0:print_stats=1"
95
Anestis Bechtsoudisa4003c52016-05-06 13:04:48 +030096/* 'log_path' output directory for sanitizer reports */
Jagger00265602016-03-10 02:36:27 +010097#define kSANLOGDIR "log_path="
98
99/* 'coverage_dir' output directory for coverage data files is set dynamically */
100#define kSANCOVDIR "coverage_dir="
101
102/*
103 * If the program ends with a signal that ASan does not handle (or can not
104 * handle at all, like SIGKILL), coverage data will be lost. This is a big
105 * problem on Android, where SIGKILL is a normal way of evicting applications
106 * from memory. With 'coverage_direct=1' coverage data is written to a
107 * memory-mapped file as soon as it collected. Non-Android targets can disable
108 * coverage direct when more coverage data collection methods are implemented.
109 */
110#if defined(__ANDROID__)
111#define kSAN_COV_OPTS "coverage=1:coverage_direct=1"
112#else
113#define kSAN_COV_OPTS "coverage=1:coverage_direct=1"
114#endif
115
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100116/*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200117 * bitmap implementation
118 */
Jagger3db1d952016-03-10 02:02:46 +0100119static bitmap_t *sancov_newBitmap(uint32_t capacity)
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200120{
Jagger679c2052016-03-18 22:53:53 +0100121 bitmap_t *pBM = util_Malloc(sizeof(bitmap_t));
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200122 pBM->capacity = capacity;
123 pBM->nChunks = (capacity + 31) / 32;
Jagger74d0d102016-03-18 22:55:59 +0100124 pBM->pChunks = util_Calloc(pBM->nChunks * sizeof(uint32_t));
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200125 return pBM;
126}
127
Jagger3db1d952016-03-10 02:02:46 +0100128static inline bool sancov_queryBitmap(bitmap_t * pBM, uint32_t index)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200129{
Anestis Bechtsoudis58c45d22016-01-10 15:05:39 +0200130 if (index > pBM->capacity) {
131 LOG_E("bitmap overflow (%u)", index);
132 return false;
133 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200134 if (pBM->pChunks[index / 32] & (1 << (index % 32))) {
135 return true;
136 }
137 return false;
138}
139
Jagger3db1d952016-03-10 02:02:46 +0100140static inline void sancov_setBitmap(bitmap_t * pBM, uint32_t index)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200141{
142 /* This will be removed. So far checks only to verify accepted ranges. */
143 if (index >= pBM->capacity) {
144 LOG_E("Out of range index (%u > %u)", index, pBM->capacity);
145 }
146 pBM->pChunks[index / 32] |= (1 << (index % 32));
147}
148
Jagger3db1d952016-03-10 02:02:46 +0100149static inline void sancov_destroyBitmap(bitmap_t * pBM)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200150{
151 free(pBM->pChunks);
152 free(pBM);
153}
154
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100155/*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200156 * Trie implementation
157 */
Jagger3db1d952016-03-10 02:02:46 +0100158static node_t *sancov_trieCreateNode(char key)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200159{
Jagger679c2052016-03-18 22:53:53 +0100160 node_t *node = (node_t *) util_Malloc(sizeof(node_t));
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200161 node->key = key;
162 node->next = NULL;
163 node->children = NULL;
164 node->parent = NULL;
165 node->prev = NULL;
166
167 /* Zero init node's data struct */
168 memset(&node->data, 0, sizeof(trieData_t));
169 return node;
170}
171
Jagger3db1d952016-03-10 02:02:46 +0100172static node_t *sancov_trieSearch(node_t * root, const char *key)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200173{
174 node_t *pNodeLevel = root, *pNodePtr = NULL;
175 int nodeLevelId = 0;
176 while (1) {
177 node_t *pNodeFound = NULL, *pCurNode = NULL;
178 for (pCurNode = pNodeLevel; pCurNode != NULL; pCurNode = pCurNode->next) {
179 if (pCurNode->key == *key) {
180 pNodeFound = pCurNode;
181 nodeLevelId++;
182 break;
183 }
184 }
185 if (pNodeFound == NULL) {
186 return NULL;
187 }
188 if (*key == '\0') {
189 pNodePtr = pCurNode;
190 return pNodePtr;
191 }
192 pNodeLevel = pNodeFound->children;
193 key++;
194 }
195}
196
Robert Swiecki40ef8402016-03-10 15:14:13 +0100197static void sancov_trieAdd(node_t ** root, const char *key)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200198{
199 if (*root == NULL) {
200 LOG_E("Invalid Trie (NULL root node)");
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200201 return;
202 }
203
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200204 /* Traverse Trie */
205 node_t *pTravNode = (*root)->children;
206 if (pTravNode == NULL) {
207 /* First node */
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200208 for (pTravNode = *root; *key != '\0'; pTravNode = pTravNode->children) {
Jagger3db1d952016-03-10 02:02:46 +0100209 pTravNode->children = sancov_trieCreateNode(*key);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200210 pTravNode->children->parent = pTravNode;
211 key++;
212 }
Jagger3db1d952016-03-10 02:02:46 +0100213 pTravNode->children = sancov_trieCreateNode('\0');
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200214 pTravNode->children->parent = pTravNode;
215 return;
216 }
217
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200218 while (*key != '\0') {
219 if (*key == pTravNode->key) {
220 key++;
221 pTravNode = pTravNode->children;
222 } else {
223 break;
224 }
225 }
226 while (pTravNode->next) {
227 if (*key == pTravNode->next->key) {
228 key++;
Robert Swiecki40ef8402016-03-10 15:14:13 +0100229 sancov_trieAdd(&(pTravNode->next), key);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200230 return;
231 }
232 pTravNode = pTravNode->next;
233 }
234 if (*key) {
Jagger3db1d952016-03-10 02:02:46 +0100235 pTravNode->next = sancov_trieCreateNode(*key);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200236 } else {
Jagger3db1d952016-03-10 02:02:46 +0100237 pTravNode->next = sancov_trieCreateNode(*key);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200238 }
239 pTravNode->next->parent = pTravNode->parent;
240 pTravNode->next->prev = pTravNode;
241 if (!*key) {
242 return;
243 }
244 key++;
245 for (pTravNode = pTravNode->next; *key; pTravNode = pTravNode->children) {
Jagger3db1d952016-03-10 02:02:46 +0100246 pTravNode->children = sancov_trieCreateNode(*key);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200247 pTravNode->children->parent = pTravNode;
248 key++;
249 }
Jagger3db1d952016-03-10 02:02:46 +0100250 pTravNode->children = sancov_trieCreateNode('\0');
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200251 pTravNode->children->parent = pTravNode;
252
253 return;
254}
255
Jagger3db1d952016-03-10 02:02:46 +0100256static inline void sancov_trieFreeNode(node_t * node)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200257{
258 /* First destroy bitmap heap buffers allocated for instrumented maps */
259 if (node->data.pBM) {
Jagger3db1d952016-03-10 02:02:46 +0100260 sancov_destroyBitmap(node->data.pBM);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200261 }
262 free(node);
263}
264
Jagger3db1d952016-03-10 02:02:46 +0100265static inline void sancov_trieCreate(node_t ** root)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200266{
267 /* Create root node if new Trie */
Jagger3db1d952016-03-10 02:02:46 +0100268 *root = sancov_trieCreateNode('\0');
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200269}
270
271/* Destroy Trie - iterate nodes and free memory */
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100272UNUSED static void sancov_trieDestroy(node_t * root)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200273{
274 node_t *pNode = root;
275 node_t *pNodeTmp = root;
276 while (pNode) {
277 while (pNode->children) {
278 pNode = pNode->children;
279 }
280
281 if (pNode->prev && pNode->next) {
282 pNodeTmp = pNode;
283 pNode->next->prev = pNode->prev;
284 pNode->prev->next = pNode->next;
Jagger3db1d952016-03-10 02:02:46 +0100285 sancov_trieFreeNode(pNodeTmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200286 } else if (pNode->prev && !pNode->next) {
287 pNodeTmp = pNode;
288 pNode->prev->next = NULL;
Jagger3db1d952016-03-10 02:02:46 +0100289 sancov_trieFreeNode(pNodeTmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200290 } else if (!pNode->prev && pNode->next) {
291 pNodeTmp = pNode;
292 pNode->parent->children = pNode->next;
293 pNode->next->prev = NULL;
294 pNode = pNode->next;
Jagger3db1d952016-03-10 02:02:46 +0100295 sancov_trieFreeNode(pNodeTmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200296 } else {
297 pNodeTmp = pNode;
298 if (pNode->parent == NULL) {
299 /* Root */
Jagger3db1d952016-03-10 02:02:46 +0100300 sancov_trieFreeNode(pNodeTmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200301 return;
302 }
303 pNode = pNode->parent;
304 pNode->children = NULL;
Jagger3db1d952016-03-10 02:02:46 +0100305 sancov_trieFreeNode(pNodeTmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200306 }
307 }
308}
309
310/* Modified interpolation search algorithm to search for nearest address fit */
Jagger3db1d952016-03-10 02:02:46 +0100311static inline uint64_t sancov_interpSearch(uint64_t * buf, uint64_t size, uint64_t key)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200312{
313 /* Avoid extra checks assuming caller always provides non-zero array size */
314 uint64_t low = 0;
315 uint64_t high = size - 1;
316 uint64_t mid = high;
317
318 while (buf[high] != buf[low] && key >= buf[low] && key <= buf[high]) {
319 mid = low + (key - buf[low]) * ((high - low) / (buf[high] - buf[low]));
320 if (buf[mid] < key) {
321 low = mid + 1;
322 } else if (key < buf[mid]) {
323 high = mid - 1;
324 } else {
325 return mid;
326 }
327 }
328 return mid;
329}
330
331/* qsort struct comparison function (memMap_t struct start addr field) */
Jagger3db1d952016-03-10 02:02:46 +0100332static int sancov_qsortCmp(const void *a, const void *b)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200333{
334 memMap_t *pA = (memMap_t *) a;
335 memMap_t *pB = (memMap_t *) b;
336 if (pA->start < pB->start) {
337 return -1;
338 } else if (pA->start > pB->start) {
339 return 1;
340 } else {
341 /* Normally we should never hit that case */
342 LOG_W("Duplicate map start addr detected");
343 return 0;
344 }
345
346}
347
Jagger3db1d952016-03-10 02:02:46 +0100348static bool sancov_sanCovParseRaw(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200349{
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200350 int dataFd = -1;
351 uint8_t *dataBuf = NULL;
352 off_t dataFileSz = 0, pos = 0;
Jaggerf26b1b62016-03-19 01:59:30 +0100353 bool is32bit = true;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200354 char covFile[PATH_MAX] = { 0 };
Jagger247c3b42016-03-21 23:24:05 +0100355 pid_t targetPid = (hfuzz->linux.pid > 0) ? hfuzz->linux.pid : fuzzer->pid;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200356
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200357 /* Fuzzer local runtime data structs - need free() before exit */
358 uint64_t *startMapsIndex = NULL;
359 memMap_t *mapsBuf = NULL;
360
361 /* Local counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200362 uint64_t nBBs = 0; /* Total BB hits found in raw file */
363 uint64_t nZeroBBs = 0; /* Number of non-hit instrumented BBs */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200364 uint64_t mapsNum = 0; /* Total number of entries in map file */
365 uint64_t noCovMapsNum = 0; /* Loaded DSOs not compiled with coverage */
366
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200367 /* File line-by-line read help buffers */
Jaggerd6f74bb2016-03-19 02:51:18 +0100368 __block char *pLine = NULL;
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200369 size_t lineSz = 0;
370
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200371 /* Coverage data analysis starts by parsing map file listing */
372 snprintf(covFile, sizeof(covFile), "%s/%s/%d.sancov.map", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200373 targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200374 if (!files_exists(covFile)) {
375 LOG_D("sancov map file not found");
376 return false;
377 }
378 FILE *fCovMap = fopen(covFile, "rb");
379 if (fCovMap == NULL) {
380 PLOG_E("Couldn't open '%s' - R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100381 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200382 }
Jagger4fe18692016-04-22 23:15:07 +0200383 defer {
384 fclose(fCovMap);
385 };
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200386
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200387 /* First line contains PC length (32/64-bit) */
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200388 if (getline(&pLine, &lineSz, fCovMap) == -1) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200389 LOG_E("Invalid map file '%s'", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100390 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200391 }
Jagger4fe18692016-04-22 23:15:07 +0200392 defer {
393 free(pLine);
394 pLine = NULL;
395 };
Jaggerf26b1b62016-03-19 01:59:30 +0100396
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200397 int pcLen = atoi(pLine);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200398 if (pcLen == 32) {
399 is32bit = true;
400 } else if (pcLen == 64) {
401 is32bit = false;
402 } else {
403 LOG_E("Invalid PC length (%d) in map file '%s'", pcLen, covFile);
404 }
Anestis Bechtsoudis1fc7cd42015-12-26 17:54:15 +0200405
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200406 /* See if #maps is available from previous run to avoid realloc inside loop */
Jaggerd34417d2016-03-16 01:26:54 +0100407 uint64_t prevMapsNum = ATOMIC_GET(hfuzz->sanCovCnts.dsoCnt);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200408 if (prevMapsNum > 0) {
Jagger679c2052016-03-18 22:53:53 +0100409 mapsBuf = util_Malloc(prevMapsNum * sizeof(memMap_t));
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200410 }
Jaggerf26b1b62016-03-19 01:59:30 +0100411 /* It's OK to free(NULL) */
Jagger4fe18692016-04-22 23:15:07 +0200412 defer {
413 free(mapsBuf);
414 };
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200415
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200416 /* Iterate map entries */
417 for (;;) {
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200418 if (getline(&pLine, &lineSz, fCovMap) == -1) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200419 break;
420 }
421
422 /* Trim trailing whitespaces, not sure if needed copied from upstream sancov.py */
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200423 char *lineEnd = pLine + strlen(pLine) - 1;
Jagger43c33e52016-03-11 22:16:26 +0100424 while (lineEnd > pLine && isspace((int)*lineEnd)) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200425 lineEnd--;
426 }
427 *(lineEnd + 1) = 0;
428
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100429 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200430 * Each line has following format:
431 * Start End Base bin/DSO name
432 * b5843000 b584e6ac b5843000 liblog.so
433 */
Jagger05c79c52016-01-31 18:00:51 +0100434 memMap_t mapData = {.start = 0 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200435 char *savePtr = NULL;
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200436 mapData.start = strtoull(strtok_r(pLine, " ", &savePtr), NULL, 16);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200437 mapData.end = strtoull(strtok_r(NULL, " ", &savePtr), NULL, 16);
438 mapData.base = strtoull(strtok_r(NULL, " ", &savePtr), NULL, 16);
439 char *mapName = strtok_r(NULL, " ", &savePtr);
440 memcpy(mapData.mapName, mapName, strlen(mapName));
441
442 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200443 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100444 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100445
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200446 /* Add entry to Trie with zero data if not already */
Jagger3db1d952016-03-10 02:02:46 +0100447 if (!sancov_trieSearch(hfuzz->covMetadata->children, mapData.mapName)) {
Robert Swiecki40ef8402016-03-10 15:14:13 +0100448 sancov_trieAdd(&hfuzz->covMetadata, mapData.mapName);
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200449 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200450 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200451
452 /* If not DSO number history (first run) or new DSO loaded, realloc local maps metadata buf */
453 if (prevMapsNum == 0 || prevMapsNum < mapsNum) {
Jaggerf49962d2016-07-21 22:49:54 +0200454 if ((mapsBuf =
455 util_Realloc(mapsBuf, (size_t) (mapsNum + 1) * sizeof(memMap_t))) == NULL) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200456 PLOG_E("realloc failed (sz=%" PRIu64 ")", (mapsNum + 1) * sizeof(memMap_t));
Jaggerf26b1b62016-03-19 01:59:30 +0100457 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200458 }
459 }
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200460
461 /* Add entry to local maps metadata array */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200462 memcpy(&mapsBuf[mapsNum], &mapData, sizeof(memMap_t));
463
464 /* Increase loaded maps counter (includes non-instrumented DSOs too) */
465 mapsNum++;
466 }
467
468 /* Delete .sancov.map file */
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200469 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100470 unlink(covFile);
471 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200472
473 /* Create a quick index array with maps start addresses */
Jagger679c2052016-03-18 22:53:53 +0100474 startMapsIndex = util_Malloc(mapsNum * sizeof(uint64_t));
Jagger4fe18692016-04-22 23:15:07 +0200475 defer {
476 free(startMapsIndex);
477 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200478
479 /* Sort quick maps index */
Jagger3db1d952016-03-10 02:02:46 +0100480 qsort(mapsBuf, mapsNum, sizeof(memMap_t), sancov_qsortCmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200481 for (size_t i = 0; i < mapsNum; i++) {
482 startMapsIndex[i] = mapsBuf[i].start;
483 }
484
485 /* mmap() .sancov.raw file */
486 snprintf(covFile, sizeof(covFile), "%s/%s/%d.sancov.raw", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200487 targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200488 dataBuf = files_mapFile(covFile, &dataFileSz, &dataFd, false);
489 if (dataBuf == NULL) {
490 LOG_E("Couldn't open and map '%s' in R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100491 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200492 }
Jagger4fe18692016-04-22 23:15:07 +0200493 defer {
494 munmap(dataBuf, dataFileSz);
495 close(dataFd);
496 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200497
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100498 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200499 * Avoid cost of size checks inside raw data read loop by defining the read function
500 * & pivot size based on PC length.
501 */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200502 uint64_t(*pReadRawBBAddrFunc) (const uint8_t *) = NULL;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200503 uint8_t pivot = 0;
504 if (is32bit) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200505 pReadRawBBAddrFunc = &util_getUINT32;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200506 pivot = 4;
507 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200508 pReadRawBBAddrFunc = &util_getUINT64;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200509 pivot = 8;
510 }
511
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100512 /*
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200513 * Take advantage of data locality (next processed addr is very likely to belong
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200514 * to same map) to avoid Trie node search for each read entry.
515 */
516 node_t *curMap = NULL;
517 uint64_t prevIndex = 0;
518
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200519 /* Iterate over data buffer containing list of hit BB addresses */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200520 while (pos < dataFileSz) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200521 uint64_t bbAddr = pReadRawBBAddrFunc(dataBuf + pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200522 pos += pivot;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200523 /* Don't bother for zero BB addr (inserted checks without hit) */
524 if (bbAddr == 0x0) {
525 nZeroBBs++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200526 continue;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200527 } else {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200528 /* Find best hit based on start addr & verify range for errors */
Jagger3db1d952016-03-10 02:02:46 +0100529 uint64_t bestFit = sancov_interpSearch(startMapsIndex, mapsNum, bbAddr);
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200530 if (bbAddr >= mapsBuf[bestFit].start && bbAddr < mapsBuf[bestFit].end) {
531 /* Increase exe/DSO total BB counter */
532 mapsBuf[bestFit].bbCnt++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200533
534 /* Update current Trie node if map changed */
535 if (curMap == NULL || (prevIndex != bestFit)) {
536 prevIndex = bestFit;
537
538 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200539 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100540 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100541
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200542 curMap =
Jagger3db1d952016-03-10 02:02:46 +0100543 sancov_trieSearch(hfuzz->covMetadata->children,
544 mapsBuf[bestFit].mapName);
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200545 if (curMap == NULL) {
546 LOG_E("Corrupted Trie - '%s' not found", mapsBuf[bestFit].mapName);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200547 continue;
548 }
549
550 /* Maintain bitmaps only for exec/DSOs with coverage enabled - allocate on first use */
551 if (curMap->data.pBM == NULL) {
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200552 LOG_D("Allocating bitmap for map '%s'", mapsBuf[bestFit].mapName);
Jagger3d977522016-08-21 19:15:59 +0200553 curMap->data.pBM = sancov_newBitmap(_HF_SANCOV_BITMAP_SIZE);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200554
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100555 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200556 * If bitmap allocation failed, unset cached Trie node ptr
557 * to execute this selection branch again.
558 */
559 if (curMap->data.pBM == NULL) {
560 curMap = NULL;
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200561 continue;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200562 }
563 }
564 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200565 }
566
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200567 /* If new relative BB addr update DSO's bitmap */
568 uint32_t relAddr = (uint32_t) (bbAddr - mapsBuf[bestFit].base);
Jagger3db1d952016-03-10 02:02:46 +0100569 if (!sancov_queryBitmap(curMap->data.pBM, relAddr)) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200570
571 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200572 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100573 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100574
Jagger3db1d952016-03-10 02:02:46 +0100575 sancov_setBitmap(curMap->data.pBM, relAddr);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200576 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200577
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200578 /* Also increase new BBs counter at worker's thread runtime data */
579 mapsBuf[bestFit].newBBCnt++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200580 }
581 } else {
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100582 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200583 * Normally this should never get executed. If hit, sanitizer
584 * coverage data collection come across some kind of bug.
585 */
Robert Swiecki37778e02016-03-15 15:45:28 +0100586 LOG_E("Invalid BB addr (%#" PRIx64 ") at offset %" PRId64, bbAddr, (uint64_t) pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200587 }
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200588 }
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200589 nBBs++;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200590 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200591
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200592 /* Finally iterate over all instrumented maps to sum-up the number of newly met BB addresses */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200593 for (uint64_t i = 0; i < mapsNum; i++) {
Robert Swiecki142f9412016-03-14 19:22:01 +0100594 if (mapsBuf[i].bbCnt > 0) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200595 fuzzer->sanCovCnts.newBBCnt += mapsBuf[i].newBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200596 } else {
597 noCovMapsNum++;
598 }
599 }
600
601 /* Successful parsing - update fuzzer worker's counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200602 fuzzer->sanCovCnts.hitBBCnt = nBBs;
603 fuzzer->sanCovCnts.totalBBCnt = nBBs + nZeroBBs;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200604 fuzzer->sanCovCnts.dsoCnt = mapsNum;
605 fuzzer->sanCovCnts.iDsoCnt = mapsNum - noCovMapsNum; /* Instrumented DSOs */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200606
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200607 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100608 unlink(covFile);
609 }
Jaggerf26b1b62016-03-19 01:59:30 +0100610 return true;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200611}
612
Jagger3db1d952016-03-10 02:02:46 +0100613static bool sancov_sanCovParse(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200614{
615 int dataFd = -1;
616 uint8_t *dataBuf = NULL;
617 off_t dataFileSz = 0, pos = 0;
618 bool is32bit = true;
619 char covFile[PATH_MAX] = { 0 };
620 DIR *pSanCovDir = NULL;
Jagger247c3b42016-03-21 23:24:05 +0100621 pid_t targetPid = (hfuzz->linux.pid > 0) ? hfuzz->linux.pid : fuzzer->pid;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200622
623 snprintf(covFile, sizeof(covFile), "%s/%s/%s.%d.sancov", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200624 files_basename(hfuzz->cmdline[0]), targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200625 if (!files_exists(covFile)) {
626 LOG_D("Target sancov file not found");
627 return false;
628 }
629
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200630 /* Local cache file suffix to use for file search of target pid data */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200631 char pidFSuffix[13] = { 0 };
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200632 snprintf(pidFSuffix, sizeof(pidFSuffix), "%d.sancov", targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200633
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200634 /* Total BBs counter summarizes all DSOs */
635 uint64_t nBBs = 0;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200636
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200637 /* Iterate sancov dir for files generated against target pid */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200638 snprintf(covFile, sizeof(covFile), "%s/%s", hfuzz->workDir, _HF_SANCOV_DIR);
639 pSanCovDir = opendir(covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100640 if (pSanCovDir == NULL) {
641 PLOG_E("opendir('%s')", covFile);
642 return false;
643 }
Jagger4fe18692016-04-22 23:15:07 +0200644 defer {
645 closedir(pSanCovDir);
646 };
Jaggerf26b1b62016-03-19 01:59:30 +0100647
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200648 struct dirent *pDir = NULL;
649 while ((pDir = readdir(pSanCovDir)) != NULL) {
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200650 /* Parse files with target's pid */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200651 if (strstr(pDir->d_name, pidFSuffix)) {
652 snprintf(covFile, sizeof(covFile), "%s/%s/%s", hfuzz->workDir, _HF_SANCOV_DIR,
653 pDir->d_name);
654 dataBuf = files_mapFile(covFile, &dataFileSz, &dataFd, false);
655 if (dataBuf == NULL) {
656 LOG_E("Couldn't open and map '%s' in R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100657 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200658 }
Jagger4fe18692016-04-22 23:15:07 +0200659 defer {
660 munmap(dataBuf, dataFileSz);
661 close(dataFd);
662 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200663
664 if (dataFileSz < 8) {
665 LOG_E("Coverage data file too short");
Jaggerf26b1b62016-03-19 01:59:30 +0100666 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200667 }
668
669 /* Check magic values & derive PC length */
670 uint64_t magic = util_getUINT64(dataBuf);
671 if (magic == kMagic32) {
672 is32bit = true;
673 } else if (magic == kMagic64) {
674 is32bit = false;
675 } else {
676 LOG_E("Invalid coverage data file");
Jaggerf26b1b62016-03-19 01:59:30 +0100677 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200678 }
679 pos += 8;
680
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100681 /*
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200682 * Avoid cost of size checks inside raw data read loop by defining the read function
683 * & pivot size based on PC length.
684 */
685 uint64_t(*pReadRawBBAddrFunc) (const uint8_t *) = NULL;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200686 uint8_t pivot = 0;
687 if (is32bit) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200688 pReadRawBBAddrFunc = &util_getUINT32;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200689 pivot = 4;
690 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200691 pReadRawBBAddrFunc = &util_getUINT64;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200692 pivot = 8;
693 }
694
695 while (pos < dataFileSz) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200696 uint32_t bbAddr = pReadRawBBAddrFunc(dataBuf + pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200697 pos += pivot;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200698 if (bbAddr == 0x0) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200699 continue;
700 }
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200701 nBBs++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200702 }
703 }
704 }
705
706 /* Successful parsing - update fuzzer worker counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200707 fuzzer->sanCovCnts.hitBBCnt = nBBs;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200708
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200709 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100710 unlink(covFile);
711 }
Jaggerf26b1b62016-03-19 01:59:30 +0100712 return true;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200713}
714
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100715/*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200716 * Sanitizer coverage data are stored in FS can be parsed via two methods:
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100717 * raw unpack & separate bin/DSO sancov file. Separate bin/DSO sancov file
718 * method is usually avoided since coverage data are lost if sanitizer unhandled
719 * signal. Additionally, the FS I/O overhead is bigger compared to raw unpack
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200720 * method which uses runtime data structures.
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100721 *
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200722 * Enabled methods are controlled from sanitizer flags in arch.c
723 */
Jagger3db1d952016-03-10 02:02:46 +0100724void sancov_Analyze(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200725{
726 if (!hfuzz->useSanCov) {
727 return;
728 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100729 /*
Anestis Bechtsoudis97633cc2016-01-13 16:25:57 +0200730 * For now supported methods are implemented in fail-over nature. This will
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200731 * change in the future when best method is concluded.
732 */
Jagger3db1d952016-03-10 02:02:46 +0100733 if (sancov_sanCovParseRaw(hfuzz, fuzzer) == false) {
734 sancov_sanCovParse(hfuzz, fuzzer);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200735 }
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200736}
Jagger00265602016-03-10 02:36:27 +0100737
738bool sancov_Init(honggfuzz_t * hfuzz)
739{
Jagger247c3b42016-03-21 23:24:05 +0100740 if (hfuzz->linux.pid > 0) {
Jagger00265602016-03-10 02:36:27 +0100741 return true;
742 }
743
Jagger00265602016-03-10 02:36:27 +0100744 /* Set sanitizer flags once to avoid performance overhead per worker spawn */
745 size_t flagsSz = 0;
746 size_t bufSz = sizeof(kASAN_OPTS) + (2 * PATH_MAX); // Larger constant + 2 dynamic paths
Jagger679c2052016-03-18 22:53:53 +0100747 char *san_opts = util_Calloc(bufSz);
Jagger4fe18692016-04-22 23:15:07 +0200748 defer {
749 free(san_opts);
750 };
Jagger00265602016-03-10 02:36:27 +0100751
752 /* AddressSanitizer (ASan) */
Jagger00265602016-03-10 02:36:27 +0100753 if (hfuzz->useSanCov) {
754#if !_HF_MONITOR_SIGABRT
755 /* Write reports in FS only if abort_on_error is disabled */
756 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s:%s%s/%s", kASAN_OPTS, kSAN_COV_OPTS,
757 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
758 kLOGPREFIX);
759#else
760 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kASAN_OPTS, kSAN_COV_OPTS,
761 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
762#endif
763 } else {
764 snprintf(san_opts, bufSz, "%s:%s%s/%s", kASAN_OPTS, kSANLOGDIR, hfuzz->workDir, kLOGPREFIX);
765 }
766
767 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100768 hfuzz->sanOpts.asanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100769 memcpy(hfuzz->sanOpts.asanOpts, san_opts, flagsSz);
770 LOG_D("ASAN_OPTIONS=%s", hfuzz->sanOpts.asanOpts);
771
772 /* Undefined Behavior (UBSan) */
773 memset(san_opts, 0, bufSz);
774 if (hfuzz->useSanCov) {
775#if !_HF_MONITOR_SIGABRT
776 /* Write reports in FS only if abort_on_error is disabled */
777 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s:%s%s/%s", kUBSAN_OPTS, kSAN_COV_OPTS,
778 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
779 kLOGPREFIX);
780#else
781 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kUBSAN_OPTS, kSAN_COV_OPTS,
782 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
783#endif
784 } else {
785 snprintf(san_opts, bufSz, "%s:%s%s/%s", kUBSAN_OPTS, kSANLOGDIR, hfuzz->workDir,
786 kLOGPREFIX);
787 }
788
789 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100790 hfuzz->sanOpts.ubsanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100791 memcpy(hfuzz->sanOpts.ubsanOpts, san_opts, flagsSz);
792 LOG_D("UBSAN_OPTIONS=%s", hfuzz->sanOpts.ubsanOpts);
793
794 /* MemorySanitizer (MSan) */
795 memset(san_opts, 0, bufSz);
796 const char *msan_reports_flag = "report_umrs=0";
797 if (hfuzz->msanReportUMRS) {
798 msan_reports_flag = "report_umrs=1";
799 }
800
801 if (hfuzz->useSanCov) {
802#if !_HF_MONITOR_SIGABRT
803 /* Write reports in FS only if abort_on_error is disabled */
804 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag,
805 kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR,
806 hfuzz->workDir, kLOGPREFIX);
807#else
808 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag,
809 kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
810#endif
811 } else {
812 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag, kSANLOGDIR,
813 hfuzz->workDir, kLOGPREFIX);
814 }
815
816 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100817 hfuzz->sanOpts.msanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100818 memcpy(hfuzz->sanOpts.msanOpts, san_opts, flagsSz);
819 LOG_D("MSAN_OPTIONS=%s", hfuzz->sanOpts.msanOpts);
820
Jagger9e7ccc12016-09-26 00:47:52 +0200821 if (hfuzz->useSanCov == false) {
822 return true;
823 }
824 sancov_trieCreate(&hfuzz->covMetadata);
825
Jagger99626d32016-09-26 00:50:14 +0200826 char sanCovOutDir[PATH_MAX] = { 0 };
827 snprintf(sanCovOutDir, sizeof(sanCovOutDir), "%s/%s", hfuzz->workDir, _HF_SANCOV_DIR);
828 if (!files_exists(sanCovOutDir)) {
829 if (mkdir(sanCovOutDir, S_IRWXU | S_IXGRP | S_IXOTH) != 0) {
830 PLOG_E("mkdir() '%s' failed", sanCovOutDir);
831 }
832 }
833
Jagger00265602016-03-10 02:36:27 +0100834 return true;
835}
Jagger2b97dc92016-03-10 04:28:18 +0100836
837bool sancov_prepareExecve(honggfuzz_t * hfuzz)
838{
839 /* Address Sanitizer (ASan) */
840 if (hfuzz->sanOpts.asanOpts) {
841 if (setenv("ASAN_OPTIONS", hfuzz->sanOpts.asanOpts, 1) == -1) {
842 PLOG_E("setenv(ASAN_OPTIONS) failed");
843 return false;
844 }
845 }
846
847 /* Memory Sanitizer (MSan) */
848 if (hfuzz->sanOpts.msanOpts) {
849 if (setenv("MSAN_OPTIONS", hfuzz->sanOpts.msanOpts, 1) == -1) {
850 PLOG_E("setenv(MSAN_OPTIONS) failed");
851 return false;
852 }
853 }
854
855 /* Undefined Behavior Sanitizer (UBSan) */
856 if (hfuzz->sanOpts.ubsanOpts) {
857 if (setenv("UBSAN_OPTIONS", hfuzz->sanOpts.ubsanOpts, 1) == -1) {
858 PLOG_E("setenv(UBSAN_OPTIONS) failed");
859 return false;
860 }
861 }
862
863 return true;
864}