blob: d31c8ed92b999f91de482213a0d1e7065390646b [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
96/* 'log_path' ouput directory for sanitizer reports */
97#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 }
Jaggerf26b1b62016-03-19 01:59:30 +0100383 DEFER(fclose(fCovMap));
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200384
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200385 /* First line contains PC length (32/64-bit) */
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200386 if (getline(&pLine, &lineSz, fCovMap) == -1) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200387 LOG_E("Invalid map file '%s'", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100388 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200389 }
Jagger799a4d42016-04-01 23:27:51 +0200390 DEFER(free(pLine);
391 pLine = NULL);
Jaggerf26b1b62016-03-19 01:59:30 +0100392
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200393 int pcLen = atoi(pLine);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200394 if (pcLen == 32) {
395 is32bit = true;
396 } else if (pcLen == 64) {
397 is32bit = false;
398 } else {
399 LOG_E("Invalid PC length (%d) in map file '%s'", pcLen, covFile);
400 }
Anestis Bechtsoudis1fc7cd42015-12-26 17:54:15 +0200401
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200402 /* See if #maps is available from previous run to avoid realloc inside loop */
Jaggerd34417d2016-03-16 01:26:54 +0100403 uint64_t prevMapsNum = ATOMIC_GET(hfuzz->sanCovCnts.dsoCnt);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200404 if (prevMapsNum > 0) {
Jagger679c2052016-03-18 22:53:53 +0100405 mapsBuf = util_Malloc(prevMapsNum * sizeof(memMap_t));
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200406 }
Jaggerf26b1b62016-03-19 01:59:30 +0100407 /* It's OK to free(NULL) */
408 DEFER(free(mapsBuf));
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200409
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200410 /* Iterate map entries */
411 for (;;) {
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200412 if (getline(&pLine, &lineSz, fCovMap) == -1) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200413 break;
414 }
415
416 /* Trim trailing whitespaces, not sure if needed copied from upstream sancov.py */
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200417 char *lineEnd = pLine + strlen(pLine) - 1;
Jagger43c33e52016-03-11 22:16:26 +0100418 while (lineEnd > pLine && isspace((int)*lineEnd)) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200419 lineEnd--;
420 }
421 *(lineEnd + 1) = 0;
422
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100423 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200424 * Each line has following format:
425 * Start End Base bin/DSO name
426 * b5843000 b584e6ac b5843000 liblog.so
427 */
Jagger05c79c52016-01-31 18:00:51 +0100428 memMap_t mapData = {.start = 0 };
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200429 char *savePtr = NULL;
Anestis Bechtsoudis267f0d82016-01-08 16:02:50 +0200430 mapData.start = strtoull(strtok_r(pLine, " ", &savePtr), NULL, 16);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200431 mapData.end = strtoull(strtok_r(NULL, " ", &savePtr), NULL, 16);
432 mapData.base = strtoull(strtok_r(NULL, " ", &savePtr), NULL, 16);
433 char *mapName = strtok_r(NULL, " ", &savePtr);
434 memcpy(mapData.mapName, mapName, strlen(mapName));
435
436 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200437 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100438 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100439
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200440 /* Add entry to Trie with zero data if not already */
Jagger3db1d952016-03-10 02:02:46 +0100441 if (!sancov_trieSearch(hfuzz->covMetadata->children, mapData.mapName)) {
Robert Swiecki40ef8402016-03-10 15:14:13 +0100442 sancov_trieAdd(&hfuzz->covMetadata, mapData.mapName);
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200443 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200444 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200445
446 /* If not DSO number history (first run) or new DSO loaded, realloc local maps metadata buf */
447 if (prevMapsNum == 0 || prevMapsNum < mapsNum) {
448 if ((mapsBuf = realloc(mapsBuf, (size_t) (mapsNum + 1) * sizeof(memMap_t))) == NULL) {
449 PLOG_E("realloc failed (sz=%" PRIu64 ")", (mapsNum + 1) * sizeof(memMap_t));
Jaggerf26b1b62016-03-19 01:59:30 +0100450 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200451 }
452 }
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200453
454 /* Add entry to local maps metadata array */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200455 memcpy(&mapsBuf[mapsNum], &mapData, sizeof(memMap_t));
456
457 /* Increase loaded maps counter (includes non-instrumented DSOs too) */
458 mapsNum++;
459 }
460
461 /* Delete .sancov.map file */
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200462 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100463 unlink(covFile);
464 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200465
466 /* Create a quick index array with maps start addresses */
Jagger679c2052016-03-18 22:53:53 +0100467 startMapsIndex = util_Malloc(mapsNum * sizeof(uint64_t));
Jaggerf26b1b62016-03-19 01:59:30 +0100468 DEFER(free(startMapsIndex));
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200469
470 /* Sort quick maps index */
Jagger3db1d952016-03-10 02:02:46 +0100471 qsort(mapsBuf, mapsNum, sizeof(memMap_t), sancov_qsortCmp);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200472 for (size_t i = 0; i < mapsNum; i++) {
473 startMapsIndex[i] = mapsBuf[i].start;
474 }
475
476 /* mmap() .sancov.raw file */
477 snprintf(covFile, sizeof(covFile), "%s/%s/%d.sancov.raw", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200478 targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200479 dataBuf = files_mapFile(covFile, &dataFileSz, &dataFd, false);
480 if (dataBuf == NULL) {
481 LOG_E("Couldn't open and map '%s' in R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100482 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200483 }
Jagger799a4d42016-04-01 23:27:51 +0200484 DEFER(munmap(dataBuf, dataFileSz); close(dataFd));
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200485
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100486 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200487 * Avoid cost of size checks inside raw data read loop by defining the read function
488 * & pivot size based on PC length.
489 */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200490 uint64_t(*pReadRawBBAddrFunc) (const uint8_t *) = NULL;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200491 uint8_t pivot = 0;
492 if (is32bit) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200493 pReadRawBBAddrFunc = &util_getUINT32;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200494 pivot = 4;
495 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200496 pReadRawBBAddrFunc = &util_getUINT64;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200497 pivot = 8;
498 }
499
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100500 /*
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200501 * Take advantage of data locality (next processed addr is very likely to belong
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200502 * to same map) to avoid Trie node search for each read entry.
503 */
504 node_t *curMap = NULL;
505 uint64_t prevIndex = 0;
506
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200507 /* Iterate over data buffer containing list of hit BB addresses */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200508 while (pos < dataFileSz) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200509 uint64_t bbAddr = pReadRawBBAddrFunc(dataBuf + pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200510 pos += pivot;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200511 /* Don't bother for zero BB addr (inserted checks without hit) */
512 if (bbAddr == 0x0) {
513 nZeroBBs++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200514 continue;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200515 } else {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200516 /* Find best hit based on start addr & verify range for errors */
Jagger3db1d952016-03-10 02:02:46 +0100517 uint64_t bestFit = sancov_interpSearch(startMapsIndex, mapsNum, bbAddr);
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200518 if (bbAddr >= mapsBuf[bestFit].start && bbAddr < mapsBuf[bestFit].end) {
519 /* Increase exe/DSO total BB counter */
520 mapsBuf[bestFit].bbCnt++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200521
522 /* Update current Trie node if map changed */
523 if (curMap == NULL || (prevIndex != bestFit)) {
524 prevIndex = bestFit;
525
526 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200527 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100528 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100529
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200530 curMap =
Jagger3db1d952016-03-10 02:02:46 +0100531 sancov_trieSearch(hfuzz->covMetadata->children,
532 mapsBuf[bestFit].mapName);
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200533 if (curMap == NULL) {
534 LOG_E("Corrupted Trie - '%s' not found", mapsBuf[bestFit].mapName);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200535 continue;
536 }
537
538 /* Maintain bitmaps only for exec/DSOs with coverage enabled - allocate on first use */
539 if (curMap->data.pBM == NULL) {
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200540 LOG_D("Allocating bitmap for map '%s'", mapsBuf[bestFit].mapName);
Jagger3db1d952016-03-10 02:02:46 +0100541 curMap->data.pBM = sancov_newBitmap(_HF_BITMAP_SIZE);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200542
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100543 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200544 * If bitmap allocation failed, unset cached Trie node ptr
545 * to execute this selection branch again.
546 */
547 if (curMap->data.pBM == NULL) {
548 curMap = NULL;
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +0200549 continue;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200550 }
551 }
552 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200553 }
554
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200555 /* If new relative BB addr update DSO's bitmap */
556 uint32_t relAddr = (uint32_t) (bbAddr - mapsBuf[bestFit].base);
Jagger3db1d952016-03-10 02:02:46 +0100557 if (!sancov_queryBitmap(curMap->data.pBM, relAddr)) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200558
559 /* Interaction with global Trie should mutex wrap to avoid threads races */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200560 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100561 MX_SCOPED_LOCK(&hfuzz->sanCov_mutex);
Robert Swiecki5d6e7342016-03-16 15:36:11 +0100562
Jagger3db1d952016-03-10 02:02:46 +0100563 sancov_setBitmap(curMap->data.pBM, relAddr);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200564 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200565
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200566 /* Also increase new BBs counter at worker's thread runtime data */
567 mapsBuf[bestFit].newBBCnt++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200568 }
569 } else {
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100570 /*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200571 * Normally this should never get executed. If hit, sanitizer
572 * coverage data collection come across some kind of bug.
573 */
Robert Swiecki37778e02016-03-15 15:45:28 +0100574 LOG_E("Invalid BB addr (%#" PRIx64 ") at offset %" PRId64, bbAddr, (uint64_t) pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200575 }
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200576 }
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200577 nBBs++;
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200578 }
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200579
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200580 /* Finally iterate over all instrumented maps to sum-up the number of newly met BB addresses */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200581 for (uint64_t i = 0; i < mapsNum; i++) {
Robert Swiecki142f9412016-03-14 19:22:01 +0100582 if (mapsBuf[i].bbCnt > 0) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200583 fuzzer->sanCovCnts.newBBCnt += mapsBuf[i].newBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200584 } else {
585 noCovMapsNum++;
586 }
587 }
588
589 /* Successful parsing - update fuzzer worker's counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200590 fuzzer->sanCovCnts.hitBBCnt = nBBs;
591 fuzzer->sanCovCnts.totalBBCnt = nBBs + nZeroBBs;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200592 fuzzer->sanCovCnts.dsoCnt = mapsNum;
593 fuzzer->sanCovCnts.iDsoCnt = mapsNum - noCovMapsNum; /* Instrumented DSOs */
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200594
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200595 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100596 unlink(covFile);
597 }
Jaggerf26b1b62016-03-19 01:59:30 +0100598 return true;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200599}
600
Jagger3db1d952016-03-10 02:02:46 +0100601static bool sancov_sanCovParse(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200602{
603 int dataFd = -1;
604 uint8_t *dataBuf = NULL;
605 off_t dataFileSz = 0, pos = 0;
606 bool is32bit = true;
607 char covFile[PATH_MAX] = { 0 };
608 DIR *pSanCovDir = NULL;
Jagger247c3b42016-03-21 23:24:05 +0100609 pid_t targetPid = (hfuzz->linux.pid > 0) ? hfuzz->linux.pid : fuzzer->pid;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200610
611 snprintf(covFile, sizeof(covFile), "%s/%s/%s.%d.sancov", hfuzz->workDir, _HF_SANCOV_DIR,
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200612 files_basename(hfuzz->cmdline[0]), targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200613 if (!files_exists(covFile)) {
614 LOG_D("Target sancov file not found");
615 return false;
616 }
617
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200618 /* Local cache file suffix to use for file search of target pid data */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200619 char pidFSuffix[13] = { 0 };
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200620 snprintf(pidFSuffix, sizeof(pidFSuffix), "%d.sancov", targetPid);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200621
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200622 /* Total BBs counter summarizes all DSOs */
623 uint64_t nBBs = 0;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200624
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200625 /* Iterate sancov dir for files generated against target pid */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200626 snprintf(covFile, sizeof(covFile), "%s/%s", hfuzz->workDir, _HF_SANCOV_DIR);
627 pSanCovDir = opendir(covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100628 if (pSanCovDir == NULL) {
629 PLOG_E("opendir('%s')", covFile);
630 return false;
631 }
632 DEFER(closedir(pSanCovDir));
633
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200634 struct dirent *pDir = NULL;
635 while ((pDir = readdir(pSanCovDir)) != NULL) {
Anestis Bechtsoudisa7c56ce2016-02-07 12:53:20 +0200636 /* Parse files with target's pid */
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200637 if (strstr(pDir->d_name, pidFSuffix)) {
638 snprintf(covFile, sizeof(covFile), "%s/%s/%s", hfuzz->workDir, _HF_SANCOV_DIR,
639 pDir->d_name);
640 dataBuf = files_mapFile(covFile, &dataFileSz, &dataFd, false);
641 if (dataBuf == NULL) {
642 LOG_E("Couldn't open and map '%s' in R/O mode", covFile);
Jaggerf26b1b62016-03-19 01:59:30 +0100643 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200644 }
Jagger799a4d42016-04-01 23:27:51 +0200645 DEFER(munmap(dataBuf, dataFileSz); close(dataFd));
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200646
647 if (dataFileSz < 8) {
648 LOG_E("Coverage data file too short");
Jaggerf26b1b62016-03-19 01:59:30 +0100649 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200650 }
651
652 /* Check magic values & derive PC length */
653 uint64_t magic = util_getUINT64(dataBuf);
654 if (magic == kMagic32) {
655 is32bit = true;
656 } else if (magic == kMagic64) {
657 is32bit = false;
658 } else {
659 LOG_E("Invalid coverage data file");
Jaggerf26b1b62016-03-19 01:59:30 +0100660 return false;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200661 }
662 pos += 8;
663
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100664 /*
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200665 * Avoid cost of size checks inside raw data read loop by defining the read function
666 * & pivot size based on PC length.
667 */
668 uint64_t(*pReadRawBBAddrFunc) (const uint8_t *) = NULL;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200669 uint8_t pivot = 0;
670 if (is32bit) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200671 pReadRawBBAddrFunc = &util_getUINT32;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200672 pivot = 4;
673 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200674 pReadRawBBAddrFunc = &util_getUINT64;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200675 pivot = 8;
676 }
677
678 while (pos < dataFileSz) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200679 uint32_t bbAddr = pReadRawBBAddrFunc(dataBuf + pos);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200680 pos += pivot;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200681 if (bbAddr == 0x0) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200682 continue;
683 }
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200684 nBBs++;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200685 }
686 }
687 }
688
689 /* Successful parsing - update fuzzer worker counters */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200690 fuzzer->sanCovCnts.hitBBCnt = nBBs;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200691
Robert Swiecki8656cbb2016-03-30 19:06:37 +0200692 if (hfuzz->linux.pid == 0 && hfuzz->persistent == false) {
Jagger1ebc6dc2016-03-12 01:39:09 +0100693 unlink(covFile);
694 }
Jaggerf26b1b62016-03-19 01:59:30 +0100695 return true;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200696}
697
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100698/*
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200699 * Sanitizer coverage data are stored in FS can be parsed via two methods:
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100700 * raw unpack & separate bin/DSO sancov file. Separate bin/DSO sancov file
701 * method is usually avoided since coverage data are lost if sanitizer unhandled
702 * signal. Additionally, the FS I/O overhead is bigger compared to raw unpack
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200703 * method which uses runtime data structures.
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100704 *
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200705 * Enabled methods are controlled from sanitizer flags in arch.c
706 */
Jagger3db1d952016-03-10 02:02:46 +0100707void sancov_Analyze(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200708{
709 if (!hfuzz->useSanCov) {
710 return;
711 }
712
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100713 /*
Anestis Bechtsoudis97633cc2016-01-13 16:25:57 +0200714 * For now supported methods are implemented in fail-over nature. This will
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200715 * change in the future when best method is concluded.
716 */
Jagger3db1d952016-03-10 02:02:46 +0100717 if (sancov_sanCovParseRaw(hfuzz, fuzzer) == false) {
718 sancov_sanCovParse(hfuzz, fuzzer);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200719 }
Anestis Bechtsoudisd76c3b82015-12-26 17:35:25 +0200720}
Jagger00265602016-03-10 02:36:27 +0100721
722bool sancov_Init(honggfuzz_t * hfuzz)
723{
Jaggerb0168a52016-03-14 21:35:28 +0100724 if (hfuzz->useSanCov == false) {
Jagger00265602016-03-10 02:36:27 +0100725 return true;
726 }
727
Jaggerb0168a52016-03-14 21:35:28 +0100728 sancov_trieCreate(&hfuzz->covMetadata);
729
Jagger247c3b42016-03-21 23:24:05 +0100730 if (hfuzz->linux.pid > 0) {
Jagger00265602016-03-10 02:36:27 +0100731 return true;
732 }
733
734 char sanCovOutDir[PATH_MAX] = { 0 };
735 snprintf(sanCovOutDir, sizeof(sanCovOutDir), "%s/%s", hfuzz->workDir, _HF_SANCOV_DIR);
736 if (!files_exists(sanCovOutDir)) {
737 if (mkdir(sanCovOutDir, S_IRWXU | S_IXGRP | S_IXOTH) != 0) {
738 PLOG_E("mkdir() '%s' failed", sanCovOutDir);
739 }
740 }
741
742 /* Set sanitizer flags once to avoid performance overhead per worker spawn */
743 size_t flagsSz = 0;
744 size_t bufSz = sizeof(kASAN_OPTS) + (2 * PATH_MAX); // Larger constant + 2 dynamic paths
Jagger679c2052016-03-18 22:53:53 +0100745 char *san_opts = util_Calloc(bufSz);
Jagger28aebbd2016-03-10 22:58:51 +0100746 DEFER(free(san_opts));
Jagger00265602016-03-10 02:36:27 +0100747
748 /* AddressSanitizer (ASan) */
Jagger00265602016-03-10 02:36:27 +0100749 if (hfuzz->useSanCov) {
750#if !_HF_MONITOR_SIGABRT
751 /* Write reports in FS only if abort_on_error is disabled */
752 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s:%s%s/%s", kASAN_OPTS, kSAN_COV_OPTS,
753 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
754 kLOGPREFIX);
755#else
756 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kASAN_OPTS, kSAN_COV_OPTS,
757 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
758#endif
759 } else {
760 snprintf(san_opts, bufSz, "%s:%s%s/%s", kASAN_OPTS, kSANLOGDIR, hfuzz->workDir, kLOGPREFIX);
761 }
762
763 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100764 hfuzz->sanOpts.asanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100765 memcpy(hfuzz->sanOpts.asanOpts, san_opts, flagsSz);
766 LOG_D("ASAN_OPTIONS=%s", hfuzz->sanOpts.asanOpts);
767
768 /* Undefined Behavior (UBSan) */
769 memset(san_opts, 0, bufSz);
770 if (hfuzz->useSanCov) {
771#if !_HF_MONITOR_SIGABRT
772 /* Write reports in FS only if abort_on_error is disabled */
773 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s:%s%s/%s", kUBSAN_OPTS, kSAN_COV_OPTS,
774 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR, hfuzz->workDir,
775 kLOGPREFIX);
776#else
777 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kUBSAN_OPTS, kSAN_COV_OPTS,
778 kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
779#endif
780 } else {
781 snprintf(san_opts, bufSz, "%s:%s%s/%s", kUBSAN_OPTS, kSANLOGDIR, hfuzz->workDir,
782 kLOGPREFIX);
783 }
784
785 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100786 hfuzz->sanOpts.ubsanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100787 memcpy(hfuzz->sanOpts.ubsanOpts, san_opts, flagsSz);
788 LOG_D("UBSAN_OPTIONS=%s", hfuzz->sanOpts.ubsanOpts);
789
790 /* MemorySanitizer (MSan) */
791 memset(san_opts, 0, bufSz);
792 const char *msan_reports_flag = "report_umrs=0";
793 if (hfuzz->msanReportUMRS) {
794 msan_reports_flag = "report_umrs=1";
795 }
796
797 if (hfuzz->useSanCov) {
798#if !_HF_MONITOR_SIGABRT
799 /* Write reports in FS only if abort_on_error is disabled */
800 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag,
801 kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR, kSANLOGDIR,
802 hfuzz->workDir, kLOGPREFIX);
803#else
804 snprintf(san_opts, bufSz, "%s:%s:%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag,
805 kSAN_COV_OPTS, kSANCOVDIR, hfuzz->workDir, _HF_SANCOV_DIR);
806#endif
807 } else {
808 snprintf(san_opts, bufSz, "%s:%s:%s%s/%s", kMSAN_OPTS, msan_reports_flag, kSANLOGDIR,
809 hfuzz->workDir, kLOGPREFIX);
810 }
811
812 flagsSz = strlen(san_opts) + 1;
Jagger679c2052016-03-18 22:53:53 +0100813 hfuzz->sanOpts.msanOpts = util_Calloc(flagsSz);
Jagger00265602016-03-10 02:36:27 +0100814 memcpy(hfuzz->sanOpts.msanOpts, san_opts, flagsSz);
815 LOG_D("MSAN_OPTIONS=%s", hfuzz->sanOpts.msanOpts);
816
817 return true;
818}
Jagger2b97dc92016-03-10 04:28:18 +0100819
820bool sancov_prepareExecve(honggfuzz_t * hfuzz)
821{
822 /* Address Sanitizer (ASan) */
823 if (hfuzz->sanOpts.asanOpts) {
824 if (setenv("ASAN_OPTIONS", hfuzz->sanOpts.asanOpts, 1) == -1) {
825 PLOG_E("setenv(ASAN_OPTIONS) failed");
826 return false;
827 }
828 }
829
830 /* Memory Sanitizer (MSan) */
831 if (hfuzz->sanOpts.msanOpts) {
832 if (setenv("MSAN_OPTIONS", hfuzz->sanOpts.msanOpts, 1) == -1) {
833 PLOG_E("setenv(MSAN_OPTIONS) failed");
834 return false;
835 }
836 }
837
838 /* Undefined Behavior Sanitizer (UBSan) */
839 if (hfuzz->sanOpts.ubsanOpts) {
840 if (setenv("UBSAN_OPTIONS", hfuzz->sanOpts.ubsanOpts, 1) == -1) {
841 PLOG_E("setenv(UBSAN_OPTIONS) failed");
842 return false;
843 }
844 }
845
846 return true;
847}