blob: 1ed4a7e2cf3c7287ac437d2668f505576be99e59 [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) {
454 if ((mapsBuf = realloc(mapsBuf, (size_t) (mapsNum + 1) * sizeof(memMap_t))) == NULL) {
455 PLOG_E("realloc failed (sz=%" PRIu64 ")", (mapsNum + 1) * sizeof(memMap_t));
Jaggerf26b1b62016-03-19 01:59:30 +0100456 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200457 }
458 }
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200459
460 /* Add entry to local maps metadata array */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200461 memcpy(&mapsBuf[mapsNum], &mapData, sizeof(memMap_t));
462
463 /* Increase loaded maps counter (includes non-instrumented DSOs too) */
464 mapsNum++;
465 }
466
467 /* Delete .sancov.map file */
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200468 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100469 unlink(covFile);
470 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200471
472 /* Create a quick index array with maps start addresses */
Jagger679c2052016-03-18 22:53:53 +0100473 startMapsIndex = util_Malloc(mapsNum * sizeof(uint64_t));
Jagger4fe18692016-04-22 23:15:07 +0200474 defer {
475 free(startMapsIndex);
476 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200477
478 /* Sort quick maps index */
Jagger3db1d952016-03-10 02:02:46 +0100479 qsort(mapsBuf, mapsNum, sizeof(memMap_t), sancov_qsortCmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200480 for (size_t i = 0; i < mapsNum; i++) {
481 startMapsIndex[i] = mapsBuf[i].start;
482 }
483
484 /* mmap() .sancov.raw file */
485 snprintf(covFile, sizeof(covFile), "%s/%s/%d.sancov.raw", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200486 targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200487 dataBuf = files_mapFile(covFile, &dataFileSz, &dataFd, false);
488 if (dataBuf == NULL) {
489 LOG_E("Couldn't open and map '%s' in R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100490 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200491 }
Jagger4fe18692016-04-22 23:15:07 +0200492 defer {
493 munmap(dataBuf, dataFileSz);
494 close(dataFd);
495 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200496
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100497 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200498 * Avoid cost of size checks inside raw data read loop by defining the read function
499 * & pivot size based on PC length.
500 */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200501 uint64_t(*pReadRawBBAddrFunc) (const uint8_t *) = NULL;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200502 uint8_t pivot = 0;
503 if (is32bit) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200504 pReadRawBBAddrFunc = &util_getUINT32;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200505 pivot = 4;
506 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200507 pReadRawBBAddrFunc = &util_getUINT64;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200508 pivot = 8;
509 }
510
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100511 /*
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200512 * Take advantage of data locality (next processed addr is very likely to belong
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200513 * to same map) to avoid Trie node search for each read entry.
514 */
515 node_t *curMap = NULL;
516 uint64_t prevIndex = 0;
517
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200518 /* Iterate over data buffer containing list of hit BB addresses */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200519 while (pos < dataFileSz) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200520 uint64_t bbAddr = pReadRawBBAddrFunc(dataBuf + pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200521 pos += pivot;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200522 /* Don't bother for zero BB addr (inserted checks without hit) */
523 if (bbAddr == 0x0) {
524 nZeroBBs++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200525 continue;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200526 } else {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200527 /* Find best hit based on start addr & verify range for errors */
Jagger3db1d952016-03-10 02:02:46 +0100528 uint64_t bestFit = sancov_interpSearch(startMapsIndex, mapsNum, bbAddr);
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200529 if (bbAddr >= mapsBuf[bestFit].start && bbAddr < mapsBuf[bestFit].end) {
530 /* Increase exe/DSO total BB counter */
531 mapsBuf[bestFit].bbCnt++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200532
533 /* Update current Trie node if map changed */
534 if (curMap == NULL || (prevIndex != bestFit)) {
535 prevIndex = bestFit;
536
537 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200538 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100539 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100540
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200541 curMap =
Jagger3db1d952016-03-10 02:02:46 +0100542 sancov_trieSearch(hfuzz->covMetadata->children,
543 mapsBuf[bestFit].mapName);
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200544 if (curMap == NULL) {
545 LOG_E("Corrupted Trie - '%s' not found", mapsBuf[bestFit].mapName);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200546 continue;
547 }
548
549 /* Maintain bitmaps only for exec/DSOs with coverage enabled - allocate on first use */
550 if (curMap->data.pBM == NULL) {
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200551 LOG_D("Allocating bitmap for map '%s'", mapsBuf[bestFit].mapName);
Jagger3db1d952016-03-10 02:02:46 +0100552 curMap->data.pBM = sancov_newBitmap(_HF_BITMAP_SIZE);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200553
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100554 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200555 * If bitmap allocation failed, unset cached Trie node ptr
556 * to execute this selection branch again.
557 */
558 if (curMap->data.pBM == NULL) {
559 curMap = NULL;
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200560 continue;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200561 }
562 }
563 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200564 }
565
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200566 /* If new relative BB addr update DSO's bitmap */
567 uint32_t relAddr = (uint32_t) (bbAddr - mapsBuf[bestFit].base);
Jagger3db1d952016-03-10 02:02:46 +0100568 if (!sancov_queryBitmap(curMap->data.pBM, relAddr)) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200569
570 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200571 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100572 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100573
Jagger3db1d952016-03-10 02:02:46 +0100574 sancov_setBitmap(curMap->data.pBM, relAddr);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200575 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200576
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200577 /* Also increase new BBs counter at worker's thread runtime data */
578 mapsBuf[bestFit].newBBCnt++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200579 }
580 } else {
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100581 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200582 * Normally this should never get executed. If hit, sanitizer
583 * coverage data collection come across some kind of bug.
584 */
Robert Swiecki37778e02016-03-15 15:45:28 +0100585 LOG_E("Invalid BB addr (%#" PRIx64 ") at offset %" PRId64, bbAddr, (uint64_t) pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200586 }
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200587 }
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200588 nBBs++;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200589 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200590
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200591 /* Finally iterate over all instrumented maps to sum-up the number of newly met BB addresses */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200592 for (uint64_t i = 0; i < mapsNum; i++) {
Robert Swiecki142f9412016-03-14 19:22:01 +0100593 if (mapsBuf[i].bbCnt > 0) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200594 fuzzer->sanCovCnts.newBBCnt += mapsBuf[i].newBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200595 } else {
596 noCovMapsNum++;
597 }
598 }
599
600 /* Successful parsing - update fuzzer worker's counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200601 fuzzer->sanCovCnts.hitBBCnt = nBBs;
602 fuzzer->sanCovCnts.totalBBCnt = nBBs + nZeroBBs;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200603 fuzzer->sanCovCnts.dsoCnt = mapsNum;
604 fuzzer->sanCovCnts.iDsoCnt = mapsNum - noCovMapsNum; /* Instrumented DSOs */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200605
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200606 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100607 unlink(covFile);
608 }
Jaggerf26b1b62016-03-19 01:59:30 +0100609 return true;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200610}
611
Jagger3db1d952016-03-10 02:02:46 +0100612static bool sancov_sanCovParse(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200613{
614 int dataFd = -1;
615 uint8_t *dataBuf = NULL;
616 off_t dataFileSz = 0, pos = 0;
617 bool is32bit = true;
618 char covFile[PATH_MAX] = { 0 };
619 DIR *pSanCovDir = NULL;
Jagger247c3b42016-03-21 23:24:05 +0100620 pid_t targetPid = (hfuzz->linux.pid > 0) ? hfuzz->linux.pid : fuzzer->pid;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200621
622 snprintf(covFile, sizeof(covFile), "%s/%s/%s.%d.sancov", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200623 files_basename(hfuzz->cmdline[0]), targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200624 if (!files_exists(covFile)) {
625 LOG_D("Target sancov file not found");
626 return false;
627 }
628
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200629 /* Local cache file suffix to use for file search of target pid data */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200630 char pidFSuffix[13] = { 0 };
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200631 snprintf(pidFSuffix, sizeof(pidFSuffix), "%d.sancov", targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200632
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200633 /* Total BBs counter summarizes all DSOs */
634 uint64_t nBBs = 0;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200635
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200636 /* Iterate sancov dir for files generated against target pid */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200637 snprintf(covFile, sizeof(covFile), "%s/%s", hfuzz->workDir, _HF_SANCOV_DIR);
638 pSanCovDir = opendir(covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100639 if (pSanCovDir == NULL) {
640 PLOG_E("opendir('%s')", covFile);
641 return false;
642 }
Jagger4fe18692016-04-22 23:15:07 +0200643 defer {
644 closedir(pSanCovDir);
645 };
Jaggerf26b1b62016-03-19 01:59:30 +0100646
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200647 struct dirent *pDir = NULL;
648 while ((pDir = readdir(pSanCovDir)) != NULL) {
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200649 /* Parse files with target's pid */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200650 if (strstr(pDir->d_name, pidFSuffix)) {
651 snprintf(covFile, sizeof(covFile), "%s/%s/%s", hfuzz->workDir, _HF_SANCOV_DIR,
652 pDir->d_name);
653 dataBuf = files_mapFile(covFile, &dataFileSz, &dataFd, false);
654 if (dataBuf == NULL) {
655 LOG_E("Couldn't open and map '%s' in R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100656 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200657 }
Jagger4fe18692016-04-22 23:15:07 +0200658 defer {
659 munmap(dataBuf, dataFileSz);
660 close(dataFd);
661 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200662
663 if (dataFileSz < 8) {
664 LOG_E("Coverage data file too short");
Jaggerf26b1b62016-03-19 01:59:30 +0100665 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200666 }
667
668 /* Check magic values & derive PC length */
669 uint64_t magic = util_getUINT64(dataBuf);
670 if (magic == kMagic32) {
671 is32bit = true;
672 } else if (magic == kMagic64) {
673 is32bit = false;
674 } else {
675 LOG_E("Invalid coverage data file");
Jaggerf26b1b62016-03-19 01:59:30 +0100676 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200677 }
678 pos += 8;
679
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100680 /*
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200681 * Avoid cost of size checks inside raw data read loop by defining the read function
682 * & pivot size based on PC length.
683 */
684 uint64_t(*pReadRawBBAddrFunc) (const uint8_t *) = NULL;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200685 uint8_t pivot = 0;
686 if (is32bit) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200687 pReadRawBBAddrFunc = &util_getUINT32;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200688 pivot = 4;
689 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200690 pReadRawBBAddrFunc = &util_getUINT64;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200691 pivot = 8;
692 }
693
694 while (pos < dataFileSz) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200695 uint32_t bbAddr = pReadRawBBAddrFunc(dataBuf + pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200696 pos += pivot;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200697 if (bbAddr == 0x0) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200698 continue;
699 }
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200700 nBBs++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200701 }
702 }
703 }
704
705 /* Successful parsing - update fuzzer worker counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200706 fuzzer->sanCovCnts.hitBBCnt = nBBs;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200707
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200708 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100709 unlink(covFile);
710 }
Jaggerf26b1b62016-03-19 01:59:30 +0100711 return true;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200712}
713
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100714/*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200715 * Sanitizer coverage data are stored in FS can be parsed via two methods:
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100716 * raw unpack & separate bin/DSO sancov file. Separate bin/DSO sancov file
717 * method is usually avoided since coverage data are lost if sanitizer unhandled
718 * signal. Additionally, the FS I/O overhead is bigger compared to raw unpack
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200719 * method which uses runtime data structures.
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100720 *
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200721 * Enabled methods are controlled from sanitizer flags in arch.c
722 */
Jagger3db1d952016-03-10 02:02:46 +0100723void sancov_Analyze(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200724{
725 if (!hfuzz->useSanCov) {
726 return;
727 }
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{
Jaggerb0168a52016-03-14 21:35:28 +0100740 if (hfuzz->useSanCov == false) {
Jagger00265602016-03-10 02:36:27 +0100741 return true;
742 }
743
Jaggerb0168a52016-03-14 21:35:28 +0100744 sancov_trieCreate(&hfuzz->covMetadata);
745
Jagger247c3b42016-03-21 23:24:05 +0100746 if (hfuzz->linux.pid > 0) {
Jagger00265602016-03-10 02:36:27 +0100747 return true;
748 }
749
750 char sanCovOutDir[PATH_MAX] = { 0 };
751 snprintf(sanCovOutDir, sizeof(sanCovOutDir), "%s/%s", hfuzz->workDir, _HF_SANCOV_DIR);
752 if (!files_exists(sanCovOutDir)) {
753 if (mkdir(sanCovOutDir, S_IRWXU | S_IXGRP | S_IXOTH) != 0) {
754 PLOG_E("mkdir() '%s' failed", sanCovOutDir);
755 }
756 }
757
758 /* Set sanitizer flags once to avoid performance overhead per worker spawn */
759 size_t flagsSz = 0;
760 size_t bufSz = sizeof(kASAN_OPTS) + (2 * PATH_MAX); // Larger constant + 2 dynamic paths
Jagger679c2052016-03-18 22:53:53 +0100761 char *san_opts = util_Calloc(bufSz);
Jagger4fe18692016-04-22 23:15:07 +0200762 defer {
763 free(san_opts);
764 };
Jagger00265602016-03-10 02:36:27 +0100765
766 /* AddressSanitizer (ASan) */
Jagger00265602016-03-10 02:36:27 +0100767 if (hfuzz->useSanCov) {
768#if !_HF_MONITOR_SIGABRT
769 /* Write reports in FS only if abort_on_error is disabled */
770 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s:%s%s/%s", kASAN_OPTS, kSAN_COV_OPTS,
771 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
772 kLOGPREFIX);
773#else
774 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kASAN_OPTS, kSAN_COV_OPTS,
775 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
776#endif
777 } else {
778 snprintf(san_opts, bufSz, "%s:%s%s/%s", kASAN_OPTS, kSANLOGDIR, hfuzz->workDir, kLOGPREFIX);
779 }
780
781 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100782 hfuzz->sanOpts.asanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100783 memcpy(hfuzz->sanOpts.asanOpts, san_opts, flagsSz);
784 LOG_D("ASAN_OPTIONS=%s", hfuzz->sanOpts.asanOpts);
785
786 /* Undefined Behavior (UBSan) */
787 memset(san_opts, 0, bufSz);
788 if (hfuzz->useSanCov) {
789#if !_HF_MONITOR_SIGABRT
790 /* Write reports in FS only if abort_on_error is disabled */
791 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s:%s%s/%s", kUBSAN_OPTS, kSAN_COV_OPTS,
792 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
793 kLOGPREFIX);
794#else
795 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kUBSAN_OPTS, kSAN_COV_OPTS,
796 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
797#endif
798 } else {
799 snprintf(san_opts, bufSz, "%s:%s%s/%s", kUBSAN_OPTS, kSANLOGDIR, hfuzz->workDir,
800 kLOGPREFIX);
801 }
802
803 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100804 hfuzz->sanOpts.ubsanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100805 memcpy(hfuzz->sanOpts.ubsanOpts, san_opts, flagsSz);
806 LOG_D("UBSAN_OPTIONS=%s", hfuzz->sanOpts.ubsanOpts);
807
808 /* MemorySanitizer (MSan) */
809 memset(san_opts, 0, bufSz);
810 const char *msan_reports_flag = "report_umrs=0";
811 if (hfuzz->msanReportUMRS) {
812 msan_reports_flag = "report_umrs=1";
813 }
814
815 if (hfuzz->useSanCov) {
816#if !_HF_MONITOR_SIGABRT
817 /* Write reports in FS only if abort_on_error is disabled */
818 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag,
819 kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR,
820 hfuzz->workDir, kLOGPREFIX);
821#else
822 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag,
823 kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
824#endif
825 } else {
826 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag, kSANLOGDIR,
827 hfuzz->workDir, kLOGPREFIX);
828 }
829
830 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100831 hfuzz->sanOpts.msanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100832 memcpy(hfuzz->sanOpts.msanOpts, san_opts, flagsSz);
833 LOG_D("MSAN_OPTIONS=%s", hfuzz->sanOpts.msanOpts);
834
835 return true;
836}
Jagger2b97dc92016-03-10 04:28:18 +0100837
838bool sancov_prepareExecve(honggfuzz_t * hfuzz)
839{
840 /* Address Sanitizer (ASan) */
841 if (hfuzz->sanOpts.asanOpts) {
842 if (setenv("ASAN_OPTIONS", hfuzz->sanOpts.asanOpts, 1) == -1) {
843 PLOG_E("setenv(ASAN_OPTIONS) failed");
844 return false;
845 }
846 }
847
848 /* Memory Sanitizer (MSan) */
849 if (hfuzz->sanOpts.msanOpts) {
850 if (setenv("MSAN_OPTIONS", hfuzz->sanOpts.msanOpts, 1) == -1) {
851 PLOG_E("setenv(MSAN_OPTIONS) failed");
852 return false;
853 }
854 }
855
856 /* Undefined Behavior Sanitizer (UBSan) */
857 if (hfuzz->sanOpts.ubsanOpts) {
858 if (setenv("UBSAN_OPTIONS", hfuzz->sanOpts.ubsanOpts, 1) == -1) {
859 PLOG_E("setenv(UBSAN_OPTIONS) failed");
860 return false;
861 }
862 }
863
864 return true;
865}