|
| 1 | +commit 30e6e00a9ab5c85b0a5a18306c390cf46684522e |
| 2 | +Author: Samuel Groß <saelo@google.com> |
| 3 | +Date: Mon Oct 14 10:36:30 2019 +0200 |
| 4 | + |
| 5 | + Initial trapfuzz implementation |
| 6 | + |
| 7 | +diff --git a/Makefile b/Makefile |
| 8 | +index c014ad25..47fd6c8a 100644 |
| 9 | +--- a/Makefile |
| 10 | ++++ b/Makefile |
| 11 | +@@ -69,7 +69,9 @@ else ifeq ($(OS),Darwin) |
| 12 | + # Figure out which crash reporter to use. |
| 13 | + CRASHWRANGLER := third_party/mac |
| 14 | + OS_VERSION := $(shell sw_vers -productVersion) |
| 15 | +- ifneq (,$(findstring 10.14,$(OS_VERSION))) |
| 16 | ++ ifneq (,$(findstring 10.15,$(OS_VERSION))) |
| 17 | ++ CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o |
| 18 | ++ else ifneq (,$(findstring 10.14,$(OS_VERSION))) |
| 19 | + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o |
| 20 | + else ifneq (,$(findstring 10.13,$(OS_VERSION))) |
| 21 | + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o |
| 22 | +diff --git a/hfuzz_cc/hfuzz-cc.c b/hfuzz_cc/hfuzz-cc.c |
| 23 | +index df985482..ed8ba0be 100644 |
| 24 | +--- a/hfuzz_cc/hfuzz-cc.c |
| 25 | ++++ b/hfuzz_cc/hfuzz-cc.c |
| 26 | +@@ -310,10 +310,10 @@ static void commonOpts(int* j, char** args) { |
| 27 | + args[(*j)++] = "-fsanitize-coverage=trace-pc,trace-cmp"; |
| 28 | + } |
| 29 | + } else { |
| 30 | +- args[(*j)++] = "-Wno-unused-command-line-argument"; |
| 31 | +- args[(*j)++] = "-fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,indirect-calls"; |
| 32 | +- args[(*j)++] = "-mllvm"; |
| 33 | +- args[(*j)++] = "-sanitizer-coverage-prune-blocks=1"; |
| 34 | ++ //args[(*j)++] = "-Wno-unused-command-line-argument"; |
| 35 | ++ //args[(*j)++] = "-fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,indirect-calls"; |
| 36 | ++ //args[(*j)++] = "-mllvm"; |
| 37 | ++ //args[(*j)++] = "-sanitizer-coverage-prune-blocks=1"; |
| 38 | + } |
| 39 | + |
| 40 | + /* |
| 41 | +diff --git a/libhfuzz/instrument.c b/libhfuzz/instrument.c |
| 42 | +index fa0a39b0..9f4224a6 100644 |
| 43 | +--- a/libhfuzz/instrument.c |
| 44 | ++++ b/libhfuzz/instrument.c |
| 45 | +@@ -4,6 +4,7 @@ |
| 46 | + #include <errno.h> |
| 47 | + #include <fcntl.h> |
| 48 | + #include <inttypes.h> |
| 49 | ++#include <signal.h> |
| 50 | + #include <stdbool.h> |
| 51 | + #include <stdint.h> |
| 52 | + #include <stdio.h> |
| 53 | +@@ -395,3 +396,172 @@ void instrumentUpdateCmpMap(uintptr_t addr, uint32_t v) { |
| 54 | + ATOMIC_POST_ADD(feedback->pidFeedbackCmp[my_thread_no], v - prev); |
| 55 | + } |
| 56 | + } |
| 57 | ++ |
| 58 | ++ |
| 59 | ++// Trapfuzz |
| 60 | ++ |
| 61 | ++// Thanks ianbeer@ |
| 62 | ++#include <mach-o/dyld_images.h> |
| 63 | ++static void* find_library_load_address(const char* library_name) { |
| 64 | ++ kern_return_t err; |
| 65 | ++ |
| 66 | ++ // get the list of all loaded modules from dyld |
| 67 | ++ // the task_info mach API will get the address of the dyld all_image_info struct for the given task |
| 68 | ++ // from which we can get the names and load addresses of all modules |
| 69 | ++ task_dyld_info_data_t task_dyld_info; |
| 70 | ++ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; |
| 71 | ++ err = task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count); |
| 72 | ++ |
| 73 | ++ const struct dyld_all_image_infos* all_image_infos = (const struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr; |
| 74 | ++ const struct dyld_image_info* image_infos = all_image_infos->infoArray; |
| 75 | ++ |
| 76 | ++ for(size_t i = 0; i < all_image_infos->infoArrayCount; i++){ |
| 77 | ++ const char* image_name = image_infos[i].imageFilePath; |
| 78 | ++ mach_vm_address_t image_load_address = (mach_vm_address_t)image_infos[i].imageLoadAddress; |
| 79 | ++ if (strstr(image_name, library_name)){ |
| 80 | ++ return (void*)image_load_address; |
| 81 | ++ } |
| 82 | ++ } |
| 83 | ++ return NULL; |
| 84 | ++} |
| 85 | ++ |
| 86 | ++// Translates the address of a trap instruction to the corresponding address in the shadow memory. |
| 87 | ++// As a basic block can be less than four bytes in size, but we need 4 bytes of storage for every patch |
| 88 | ++// (3 byte bitmap index, 1 byte original value), we create 4 shadow mappings and select the correct one |
| 89 | ++// from the last 2 bits of the address. |
| 90 | ++#define SHADOW(addr) ((uint32_t*)(((uintptr_t)addr & 0xfffffffffffffffc) - 0x200000000000 - ((uintptr_t)addr & 0x3)*0x10000000000)) |
| 91 | ++ |
| 92 | ++static void sigtrap_handler(int signum, siginfo_t* si, void* context) { |
| 93 | ++ // Must re-execute the instruction, so decrement PC by one instruction. |
| 94 | ++#if defined(__APPLE__) && defined(__LP64__) |
| 95 | ++ ucontext_t* ctx = (ucontext_t*)context; |
| 96 | ++ ctx->uc_mcontext->__ss.__rip -= 1; |
| 97 | ++#else |
| 98 | ++#error "Unsupported platform" |
| 99 | ++#endif |
| 100 | ++ |
| 101 | ++ uint8_t* faultaddr = (uint8_t*)si->si_addr - 1; |
| 102 | ++ // If the trap didn't come from our instrumentation, then we probably will just segfault here |
| 103 | ++ uint32_t shadow = *SHADOW(faultaddr); |
| 104 | ++ |
| 105 | ++ uint8_t orig_byte = shadow & 0xff; |
| 106 | ++ uint32_t index = shadow >> 8; |
| 107 | ++ |
| 108 | ++ // Index zero is invalid so that it is still possible to catch actual trap instructions in instrumented libraries. |
| 109 | ++ if (index == 0) { |
| 110 | ++ abort(); |
| 111 | ++ } |
| 112 | ++ |
| 113 | ++ // Restore original instruction |
| 114 | ++ *faultaddr = orig_byte; |
| 115 | ++ |
| 116 | ++ // Update coverage information. |
| 117 | ++ bool prev = ATOMIC_XCHG(feedback->pcGuardMap[index], true); |
| 118 | ++ if (prev == false) { |
| 119 | ++ ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackEdge[my_thread_no]); |
| 120 | ++ } |
| 121 | ++} |
| 122 | ++ |
| 123 | ++void initializeTrapfuzz() { |
| 124 | ++ char* filename = getenv("TRAPFUZZ_FILE"); // TODO rename maybe? |
| 125 | ++ if (!filename) { |
| 126 | ++ LOG_F("TRAPFUZZ_FILE environment variable not set"); |
| 127 | ++ } |
| 128 | ++ |
| 129 | ++ FILE* patches = fopen(filename, "r"); |
| 130 | ++ if (!patches) { |
| 131 | ++ LOG_F("Couldn't open patchfile %s", filename); |
| 132 | ++ } |
| 133 | ++ |
| 134 | ++ // Index into the coverage bitmap for the current trap instruction. |
| 135 | ++ int bitmap_index = -1; |
| 136 | ++ |
| 137 | ++ // Base address of the library currently being instrumented. |
| 138 | ++ uint8_t* lib_base = NULL; |
| 139 | ++ // Size of the library, or rather it's .text section which will be modified and thus has to be mprotect'ed. |
| 140 | ++ size_t lib_size = 0; |
| 141 | ++ |
| 142 | ++ char* line = NULL; |
| 143 | ++ size_t nread, len = 0; |
| 144 | ++ while ((nread = getline(&line, &len, patches)) != -1) { |
| 145 | ++ char* end = line + len; |
| 146 | ++ |
| 147 | ++ char* col = strchr(line, ':'); |
| 148 | ++ if (col) { |
| 149 | ++ // It's a library:size pair |
| 150 | ++ *col = 0; |
| 151 | ++ |
| 152 | ++ lib_base = find_library_load_address(line); |
| 153 | ++ if (!lib_base) { |
| 154 | ++ LOG_F("Library %s does not appear to be loaded", line); |
| 155 | ++ } |
| 156 | ++ |
| 157 | ++ lib_size = strtoul(col + 1, &end, 16); |
| 158 | ++ if (lib_size % 0x1000 != 0) { |
| 159 | ++ LOG_F("Invalid library size 0x%zx. Must be multiple of 0x1000", lib_size); |
| 160 | ++ } |
| 161 | ++ |
| 162 | ++ // Make library code writable. |
| 163 | ++ if (mprotect(lib_base, lib_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) { |
| 164 | ++ LOG_F("Failed to mprotect library %s writable", line); |
| 165 | ++ } |
| 166 | ++ |
| 167 | ++ // Create shadow memory. |
| 168 | ++ for (int i = 0; i < 4; i++) { |
| 169 | ++ void* shadow_addr = SHADOW(lib_base + i); |
| 170 | ++ void* shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0); |
| 171 | ++ if (shadow == MAP_FAILED) { |
| 172 | ++ LOG_F("Failed to mmap shadow memory"); |
| 173 | ++ } |
| 174 | ++ } |
| 175 | ++ |
| 176 | ++ // Done, continue with next line. |
| 177 | ++ continue; |
| 178 | ++ } |
| 179 | ++ |
| 180 | ++ // It's an offset, parse it and do the patching. |
| 181 | ++ unsigned long offset = strtoul(line, &end, 16); |
| 182 | ++ if (offset > lib_size) { |
| 183 | ++ LOG_F("Invalid offset: 0x%lx. Current library is 0x%zx bytes large", offset, lib_size); |
| 184 | ++ } |
| 185 | ++ |
| 186 | ++ bitmap_index++; |
| 187 | ++ |
| 188 | ++ if (bitmap_index >= _HF_PC_GUARD_MAX) { |
| 189 | ++ LOG_F("Too many basic blocks to instrument"); |
| 190 | ++ } |
| 191 | ++ |
| 192 | ++ uint32_t* shadow = SHADOW(lib_base + offset); |
| 193 | ++ if (*shadow != 0) { |
| 194 | ++ LOG_F("Potentially duplicate patch entry: 0x%lx", offset); |
| 195 | ++ } |
| 196 | ++ |
| 197 | ++ if (ATOMIC_GET(feedback->pcGuardMap[bitmap_index])) { |
| 198 | ++ // This instrumentation trap has already been found. |
| 199 | ++ continue; |
| 200 | ++ } |
| 201 | ++ |
| 202 | ++ // Make lookup entry in shadow memory. |
| 203 | ++ uint8_t orig_byte = lib_base[offset]; |
| 204 | ++ *shadow = (bitmap_index << 8) | orig_byte; |
| 205 | ++ |
| 206 | ++ // Replace instruction with int3, an instrumentation trap. |
| 207 | ++ lib_base[offset] = 0xcc; |
| 208 | ++ } |
| 209 | ++ |
| 210 | ++ // Store number of basic blocks for statistical purposes. |
| 211 | ++ if (ATOMIC_GET(feedback->guardNb) < bitmap_index + 1) { |
| 212 | ++ ATOMIC_SET(feedback->guardNb, bitmap_index + 1); |
| 213 | ++ } |
| 214 | ++ |
| 215 | ++ free(line); |
| 216 | ++ fclose(patches); |
| 217 | ++ |
| 218 | ++ // Install signal handler for SIGTRAP. |
| 219 | ++ struct sigaction s; |
| 220 | ++ s.sa_flags = SA_SIGINFO; // TODO add SA_NODEFER? |
| 221 | ++ s.sa_sigaction = sigtrap_handler; |
| 222 | ++ sigemptyset(&s.sa_mask); |
| 223 | ++ sigaction(SIGTRAP, &s, 0); |
| 224 | ++} |
| 225 | ++ |
| 226 | +diff --git a/libhfuzz/instrument.h b/libhfuzz/instrument.h |
| 227 | +index 87647fce..e073222f 100644 |
| 228 | +--- a/libhfuzz/instrument.h |
| 229 | ++++ b/libhfuzz/instrument.h |
| 230 | +@@ -29,4 +29,6 @@ |
| 231 | + void instrumentUpdateCmpMap(uintptr_t addr, uint32_t v); |
| 232 | + void instrumentClearNewCov(); |
| 233 | + |
| 234 | ++void initializeTrapfuzz(); |
| 235 | ++ |
| 236 | + #endif /* ifdef _HF_LIBHFUZZ_INSTRUMENT_H_ */ |
0 commit comments