Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 1 | //===-- dfsan.cc ----------------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of DataFlowSanitizer. |
| 11 | // |
| 12 | // DataFlowSanitizer runtime. This file defines the public interface to |
| 13 | // DataFlowSanitizer as well as the definition of certain runtime functions |
| 14 | // called automatically by the compiler (specifically the instrumentation pass |
| 15 | // in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp). |
| 16 | // |
| 17 | // The public interface is defined in include/sanitizer/dfsan_interface.h whose |
| 18 | // functions are prefixed dfsan_ while the compiler interface functions are |
| 19 | // prefixed __dfsan_. |
| 20 | //===----------------------------------------------------------------------===// |
| 21 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 22 | #include "sanitizer_common/sanitizer_atomic.h" |
| 23 | #include "sanitizer_common/sanitizer_common.h" |
Peter Collingbourne | 78d737c | 2013-09-10 01:51:35 +0000 | [diff] [blame] | 24 | #include "sanitizer_common/sanitizer_flags.h" |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 25 | #include "sanitizer_common/sanitizer_flag_parser.h" |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 26 | #include "sanitizer_common/sanitizer_libc.h" |
| 27 | |
Peter Collingbourne | fa9f5ae | 2013-08-12 23:51:33 +0000 | [diff] [blame] | 28 | #include "dfsan/dfsan.h" |
| 29 | |
| 30 | using namespace __dfsan; |
| 31 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 32 | typedef atomic_uint16_t atomic_dfsan_label; |
| 33 | static const dfsan_label kInitializingLabel = -1; |
| 34 | |
| 35 | static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8); |
| 36 | |
| 37 | static atomic_dfsan_label __dfsan_last_label; |
| 38 | static dfsan_label_info __dfsan_label_info[kNumLabels]; |
| 39 | |
Peter Collingbourne | 78d737c | 2013-09-10 01:51:35 +0000 | [diff] [blame] | 40 | Flags __dfsan::flags_data; |
| 41 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 42 | SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls; |
| 43 | SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; |
| 44 | |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 45 | SANITIZER_INTERFACE_ATTRIBUTE uptr __dfsan_shadow_ptr_mask; |
| 46 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 47 | // On Linux/x86_64, memory is laid out as follows: |
| 48 | // |
| 49 | // +--------------------+ 0x800000000000 (top of memory) |
| 50 | // | application memory | |
| 51 | // +--------------------+ 0x700000008000 (kAppAddr) |
| 52 | // | | |
| 53 | // | unused | |
| 54 | // | | |
| 55 | // +--------------------+ 0x200200000000 (kUnusedAddr) |
| 56 | // | union table | |
| 57 | // +--------------------+ 0x200000000000 (kUnionTableAddr) |
| 58 | // | shadow memory | |
| 59 | // +--------------------+ 0x000000010000 (kShadowAddr) |
| 60 | // | reserved by kernel | |
| 61 | // +--------------------+ 0x000000000000 |
| 62 | // |
| 63 | // To derive a shadow memory address from an application memory address, |
| 64 | // bits 44-46 are cleared to bring the address into the range |
| 65 | // [0x000000008000,0x100000000000). Then the address is shifted left by 1 to |
| 66 | // account for the double byte representation of shadow labels and move the |
| 67 | // address into the shadow memory range. See the function shadow_for below. |
| 68 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 69 | // On Linux/MIPS64, memory is laid out as follows: |
| 70 | // |
| 71 | // +--------------------+ 0x10000000000 (top of memory) |
| 72 | // | application memory | |
| 73 | // +--------------------+ 0xF000008000 (kAppAddr) |
| 74 | // | | |
| 75 | // | unused | |
| 76 | // | | |
| 77 | // +--------------------+ 0x2200000000 (kUnusedAddr) |
| 78 | // | union table | |
| 79 | // +--------------------+ 0x2000000000 (kUnionTableAddr) |
| 80 | // | shadow memory | |
| 81 | // +--------------------+ 0x0000010000 (kShadowAddr) |
| 82 | // | reserved by kernel | |
| 83 | // +--------------------+ 0x0000000000 |
| 84 | |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 85 | // On Linux/AArch64 (39-bit VMA), memory is laid out as follow: |
| 86 | // |
| 87 | // +--------------------+ 0x8000000000 (top of memory) |
| 88 | // | application memory | |
| 89 | // +--------------------+ 0x7000008000 (kAppAddr) |
| 90 | // | | |
| 91 | // | unused | |
| 92 | // | | |
| 93 | // +--------------------+ 0x1200000000 (kUnusedAddr) |
| 94 | // | union table | |
| 95 | // +--------------------+ 0x1000000000 (kUnionTableAddr) |
| 96 | // | shadow memory | |
| 97 | // +--------------------+ 0x0000010000 (kShadowAddr) |
| 98 | // | reserved by kernel | |
| 99 | // +--------------------+ 0x0000000000 |
| 100 | |
| 101 | // On Linux/AArch64 (42-bit VMA), memory is laid out as follow: |
| 102 | // |
| 103 | // +--------------------+ 0x40000000000 (top of memory) |
| 104 | // | application memory | |
| 105 | // +--------------------+ 0x3ff00008000 (kAppAddr) |
| 106 | // | | |
| 107 | // | unused | |
| 108 | // | | |
| 109 | // +--------------------+ 0x1200000000 (kUnusedAddr) |
| 110 | // | union table | |
| 111 | // +--------------------+ 0x8000000000 (kUnionTableAddr) |
| 112 | // | shadow memory | |
| 113 | // +--------------------+ 0x0000010000 (kShadowAddr) |
| 114 | // | reserved by kernel | |
| 115 | // +--------------------+ 0x0000000000 |
| 116 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 117 | typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels]; |
| 118 | |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 119 | #ifdef DFSAN_RUNTIME_VMA |
| 120 | // Runtime detected VMA size. |
| 121 | int __dfsan::vmaSize; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 122 | #endif |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 123 | |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 124 | static uptr UnusedAddr() { |
| 125 | return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>() |
| 126 | + sizeof(dfsan_union_table_t); |
| 127 | } |
| 128 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 129 | static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) { |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 130 | return &(*(dfsan_union_table_t *) UnionTableAddr())[l1][l2]; |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 131 | } |
| 132 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 133 | // Checks we do not run out of labels. |
| 134 | static void dfsan_check_label(dfsan_label label) { |
| 135 | if (label == kInitializingLabel) { |
| 136 | Report("FATAL: DataFlowSanitizer: out of labels\n"); |
| 137 | Die(); |
| 138 | } |
| 139 | } |
| 140 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 141 | // Resolves the union of two unequal labels. Nonequality is a precondition for |
| 142 | // this function (the instrumentation pass inlines the equality test). |
| 143 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE |
| 144 | dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) { |
| 145 | DCHECK_NE(l1, l2); |
| 146 | |
| 147 | if (l1 == 0) |
| 148 | return l2; |
| 149 | if (l2 == 0) |
| 150 | return l1; |
| 151 | |
| 152 | if (l1 > l2) |
| 153 | Swap(l1, l2); |
| 154 | |
| 155 | atomic_dfsan_label *table_ent = union_table(l1, l2); |
| 156 | // We need to deal with the case where two threads concurrently request |
| 157 | // a union of the same pair of labels. If the table entry is uninitialized, |
| 158 | // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel |
| 159 | // (i.e. -1) to mark that we are initializing it. |
| 160 | dfsan_label label = 0; |
| 161 | if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel, |
| 162 | memory_order_acquire)) { |
| 163 | // Check whether l2 subsumes l1. We don't need to check whether l1 |
| 164 | // subsumes l2 because we are guaranteed here that l1 < l2, and (at least |
| 165 | // in the cases we are interested in) a label may only subsume labels |
| 166 | // created earlier (i.e. with a lower numerical value). |
| 167 | if (__dfsan_label_info[l2].l1 == l1 || |
| 168 | __dfsan_label_info[l2].l2 == l1) { |
| 169 | label = l2; |
| 170 | } else { |
| 171 | label = |
| 172 | atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 173 | dfsan_check_label(label); |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 174 | __dfsan_label_info[label].l1 = l1; |
| 175 | __dfsan_label_info[label].l2 = l2; |
| 176 | } |
| 177 | atomic_store(table_ent, label, memory_order_release); |
| 178 | } else if (label == kInitializingLabel) { |
| 179 | // Another thread is initializing the entry. Wait until it is finished. |
| 180 | do { |
| 181 | internal_sched_yield(); |
| 182 | label = atomic_load(table_ent, memory_order_acquire); |
| 183 | } while (label == kInitializingLabel); |
| 184 | } |
| 185 | return label; |
| 186 | } |
| 187 | |
| 188 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 189 | dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) { |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 190 | dfsan_label label = ls[0]; |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 191 | for (uptr i = 1; i != n; ++i) { |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 192 | dfsan_label next_label = ls[i]; |
| 193 | if (label != next_label) |
| 194 | label = __dfsan_union(label, next_label); |
| 195 | } |
| 196 | return label; |
| 197 | } |
| 198 | |
Peter Collingbourne | e8d2034 | 2013-08-14 18:54:06 +0000 | [diff] [blame] | 199 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE |
| 200 | void __dfsan_unimplemented(char *fname) { |
Peter Collingbourne | 78d737c | 2013-09-10 01:51:35 +0000 | [diff] [blame] | 201 | if (flags().warn_unimplemented) |
| 202 | Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n", |
| 203 | fname); |
Peter Collingbourne | e8d2034 | 2013-08-14 18:54:06 +0000 | [diff] [blame] | 204 | } |
| 205 | |
Peter Collingbourne | 2c78b04 | 2013-08-15 18:51:07 +0000 | [diff] [blame] | 206 | // Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function |
| 207 | // to try to figure out where labels are being introduced in a nominally |
| 208 | // label-free program. |
Peter Collingbourne | 78d737c | 2013-09-10 01:51:35 +0000 | [diff] [blame] | 209 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() { |
| 210 | if (flags().warn_nonzero_labels) |
| 211 | Report("WARNING: DataFlowSanitizer: saw nonzero label\n"); |
| 212 | } |
Peter Collingbourne | 2c78b04 | 2013-08-15 18:51:07 +0000 | [diff] [blame] | 213 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 214 | // Indirect call to an uninstrumented vararg function. We don't have a way of |
| 215 | // handling these at the moment. |
| 216 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
| 217 | __dfsan_vararg_wrapper(const char *fname) { |
| 218 | Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg " |
| 219 | "function %s\n", fname); |
| 220 | Die(); |
| 221 | } |
| 222 | |
Peter Collingbourne | 249cdca | 2013-08-12 23:47:37 +0000 | [diff] [blame] | 223 | // Like __dfsan_union, but for use from the client or custom functions. Hence |
| 224 | // the equality comparison is done here before calling __dfsan_union. |
| 225 | SANITIZER_INTERFACE_ATTRIBUTE dfsan_label |
| 226 | dfsan_union(dfsan_label l1, dfsan_label l2) { |
| 227 | if (l1 == l2) |
| 228 | return l1; |
| 229 | return __dfsan_union(l1, l2); |
| 230 | } |
| 231 | |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 232 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 233 | dfsan_label dfsan_create_label(const char *desc, void *userdata) { |
| 234 | dfsan_label label = |
| 235 | atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 236 | dfsan_check_label(label); |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 237 | __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0; |
| 238 | __dfsan_label_info[label].desc = desc; |
| 239 | __dfsan_label_info[label].userdata = userdata; |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 240 | return label; |
| 241 | } |
| 242 | |
Peter Collingbourne | 369ffff | 2013-08-14 20:51:33 +0000 | [diff] [blame] | 243 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 244 | void __dfsan_set_label(dfsan_label label, void *addr, uptr size) { |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 245 | for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) { |
| 246 | // Don't write the label if it is already the value we need it to be. |
| 247 | // In a program where most addresses are not labeled, it is common that |
| 248 | // a page of shadow memory is entirely zeroed. The Linux copy-on-write |
| 249 | // implementation will share all of the zeroed pages, making a copy of a |
| 250 | // page when any value is written. The un-sharing will happen even if |
| 251 | // the value written does not change the value in memory. Avoiding the |
| 252 | // write when both |label| and |*labelp| are zero dramatically reduces |
| 253 | // the amount of real memory used by large programs. |
| 254 | if (label == *labelp) |
| 255 | continue; |
| 256 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 257 | *labelp = label; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 258 | } |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 259 | } |
| 260 | |
| 261 | SANITIZER_INTERFACE_ATTRIBUTE |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 262 | void dfsan_set_label(dfsan_label label, void *addr, uptr size) { |
Peter Collingbourne | 369ffff | 2013-08-14 20:51:33 +0000 | [diff] [blame] | 263 | __dfsan_set_label(label, addr, size); |
| 264 | } |
| 265 | |
| 266 | SANITIZER_INTERFACE_ATTRIBUTE |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 267 | void dfsan_add_label(dfsan_label label, void *addr, uptr size) { |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 268 | for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) |
| 269 | if (*labelp != label) |
| 270 | *labelp = __dfsan_union(*labelp, label); |
| 271 | } |
| 272 | |
Peter Collingbourne | e8d2034 | 2013-08-14 18:54:06 +0000 | [diff] [blame] | 273 | // Unlike the other dfsan interface functions the behavior of this function |
| 274 | // depends on the label of one of its arguments. Hence it is implemented as a |
| 275 | // custom function. |
| 276 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label |
| 277 | __dfsw_dfsan_get_label(long data, dfsan_label data_label, |
| 278 | dfsan_label *ret_label) { |
| 279 | *ret_label = 0; |
| 280 | return data_label; |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 281 | } |
| 282 | |
Peter Collingbourne | 1528c6c | 2013-08-13 22:15:40 +0000 | [diff] [blame] | 283 | SANITIZER_INTERFACE_ATTRIBUTE dfsan_label |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 284 | dfsan_read_label(const void *addr, uptr size) { |
Peter Collingbourne | 1528c6c | 2013-08-13 22:15:40 +0000 | [diff] [blame] | 285 | if (size == 0) |
| 286 | return 0; |
| 287 | return __dfsan_union_load(shadow_for(addr), size); |
| 288 | } |
| 289 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 290 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 291 | const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) { |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 292 | return &__dfsan_label_info[label]; |
| 293 | } |
| 294 | |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 295 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE int |
| 296 | dfsan_has_label(dfsan_label label, dfsan_label elem) { |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 297 | if (label == elem) |
| 298 | return true; |
| 299 | const dfsan_label_info *info = dfsan_get_label_info(label); |
| 300 | if (info->l1 != 0) { |
| 301 | return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem); |
| 302 | } else { |
| 303 | return false; |
| 304 | } |
| 305 | } |
| 306 | |
Alexey Samsonov | c85d627 | 2013-11-17 09:41:47 +0000 | [diff] [blame] | 307 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label |
| 308 | dfsan_has_label_with_desc(dfsan_label label, const char *desc) { |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 309 | const dfsan_label_info *info = dfsan_get_label_info(label); |
| 310 | if (info->l1 != 0) { |
| 311 | return dfsan_has_label_with_desc(info->l1, desc) || |
| 312 | dfsan_has_label_with_desc(info->l2, desc); |
| 313 | } else { |
| 314 | return internal_strcmp(desc, info->desc) == 0; |
| 315 | } |
| 316 | } |
| 317 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 318 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr |
| 319 | dfsan_get_label_count(void) { |
| 320 | dfsan_label max_label_allocated = |
| 321 | atomic_load(&__dfsan_last_label, memory_order_relaxed); |
| 322 | |
| 323 | return static_cast<uptr>(max_label_allocated); |
| 324 | } |
| 325 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 326 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
| 327 | dfsan_dump_labels(int fd) { |
| 328 | dfsan_label last_label = |
| 329 | atomic_load(&__dfsan_last_label, memory_order_relaxed); |
| 330 | |
| 331 | for (uptr l = 1; l <= last_label; ++l) { |
| 332 | char buf[64]; |
| 333 | internal_snprintf(buf, sizeof(buf), "%u %u %u ", l, |
| 334 | __dfsan_label_info[l].l1, __dfsan_label_info[l].l2); |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 335 | WriteToFile(fd, buf, internal_strlen(buf)); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 336 | if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) { |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 337 | WriteToFile(fd, __dfsan_label_info[l].desc, |
| 338 | internal_strlen(__dfsan_label_info[l].desc)); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 339 | } |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 340 | WriteToFile(fd, "\n", 1); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 341 | } |
| 342 | } |
| 343 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 344 | void Flags::SetDefaults() { |
| 345 | #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; |
| 346 | #include "dfsan_flags.inc" |
| 347 | #undef DFSAN_FLAG |
| 348 | } |
Peter Collingbourne | 78d737c | 2013-09-10 01:51:35 +0000 | [diff] [blame] | 349 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 350 | static void RegisterDfsanFlags(FlagParser *parser, Flags *f) { |
| 351 | #define DFSAN_FLAG(Type, Name, DefaultValue, Description) \ |
| 352 | RegisterFlag(parser, #Name, Description, &f->Name); |
| 353 | #include "dfsan_flags.inc" |
| 354 | #undef DFSAN_FLAG |
| 355 | } |
| 356 | |
| 357 | static void InitializeFlags() { |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 358 | SetCommonFlagsDefaults(); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 359 | flags().SetDefaults(); |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 360 | |
| 361 | FlagParser parser; |
| 362 | RegisterCommonFlags(&parser); |
| 363 | RegisterDfsanFlags(&parser, &flags()); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 364 | parser.ParseString(GetEnv("DFSAN_OPTIONS")); |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 365 | SetVerbosity(common_flags()->verbosity); |
| 366 | if (Verbosity()) ReportUnrecognizedFlags(); |
| 367 | if (common_flags()->help) parser.PrintFlagDescriptions(); |
| 368 | } |
| 369 | |
| 370 | static void InitializePlatformEarly() { |
| 371 | #ifdef DFSAN_RUNTIME_VMA |
| 372 | __dfsan::vmaSize = |
| 373 | (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); |
| 374 | if (__dfsan::vmaSize == 39 || __dfsan::vmaSize == 42) { |
| 375 | __dfsan_shadow_ptr_mask = ShadowMask(); |
| 376 | } else { |
| 377 | Printf("FATAL: DataFlowSanitizer: unsupported VMA range\n"); |
| 378 | Printf("FATAL: Found %d - Supported 39 and 42\n", __dfsan::vmaSize); |
| 379 | Die(); |
| 380 | } |
| 381 | #endif |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 382 | } |
| 383 | |
| 384 | static void dfsan_fini() { |
| 385 | if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) { |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 386 | fd_t fd = OpenFile(flags().dump_labels_at_exit, WrOnly); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 387 | if (fd == kInvalidFd) { |
| 388 | Report("WARNING: DataFlowSanitizer: unable to open output file %s\n", |
| 389 | flags().dump_labels_at_exit); |
| 390 | return; |
| 391 | } |
| 392 | |
| 393 | Report("INFO: DataFlowSanitizer: dumping labels to %s\n", |
| 394 | flags().dump_labels_at_exit); |
| 395 | dfsan_dump_labels(fd); |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 396 | CloseFile(fd); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 397 | } |
Peter Collingbourne | 78d737c | 2013-09-10 01:51:35 +0000 | [diff] [blame] | 398 | } |
| 399 | |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 400 | static void dfsan_init(int argc, char **argv, char **envp) { |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 401 | InitializeFlags(); |
| 402 | |
| 403 | InitializePlatformEarly(); |
| 404 | |
| 405 | MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()); |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 406 | |
| 407 | // Protect the region of memory we don't use, to preserve the one-to-one |
| 408 | // mapping from application to shadow memory. But if ASLR is disabled, Linux |
| 409 | // will load our executable in the middle of our unused region. This mostly |
| 410 | // works so long as the program doesn't use too much memory. We support this |
| 411 | // case by disabling memory protection when ASLR is disabled. |
| 412 | uptr init_addr = (uptr)&dfsan_init; |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 413 | if (!(init_addr >= UnusedAddr() && init_addr < AppAddr())) |
| 414 | MmapNoAccess(UnusedAddr(), AppAddr() - UnusedAddr()); |
Peter Collingbourne | 6e4c46d | 2013-08-15 21:18:53 +0000 | [diff] [blame] | 415 | |
| 416 | InitializeInterceptors(); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 417 | |
| 418 | // Register the fini callback to run when the program terminates successfully |
| 419 | // or it is killed by the runtime. |
| 420 | Atexit(dfsan_fini); |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 421 | AddDieCallback(dfsan_fini); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 422 | |
| 423 | __dfsan_label_info[kInitializingLabel].desc = "<init label>"; |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 424 | } |
| 425 | |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 426 | #if SANITIZER_CAN_USE_PREINIT_ARRAY |
Peter Collingbourne | eee71ae | 2013-08-07 22:47:26 +0000 | [diff] [blame] | 427 | __attribute__((section(".preinit_array"), used)) |
| 428 | static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init; |
| 429 | #endif |