1 //===-- msandr.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 MemorySanitizer. 11 // 12 // DynamoRio client for MemorySanitizer. 13 // 14 // MemorySanitizer requires that all program code is instrumented. Any memory 15 // store that can turn an uninitialized value into an initialized value must be 16 // observed by the tool, otherwise we risk reporting a false UMR. 17 // 18 // This also includes any libraries that the program depends on. 19 // 20 // In the case when rebuilding all program dependencies with MemorySanitizer is 21 // problematic, an experimental MSanDR tool (the code you are currently looking 22 // at) can be used. It is a DynamoRio-based tool that uses dynamic 23 // instrumentation to 24 // * Unpoison all memory stores. 25 // * Unpoison TLS slots used by MemorySanitizer to pass function arguments and 26 // return value shadow on anything that looks like a function call or a return 27 // from a function. 28 // 29 // This tool does not detect the use of uninitialized values in uninstrumented 30 // libraries. It merely gets rid of false positives by marking all data that 31 // passes through uninstrumented code as fully initialized. 32 //===----------------------------------------------------------------------===// 33 34 #include <dr_api.h> 35 #include <drutil.h> 36 #include <drmgr.h> 37 #include <drsyscall.h> 38 39 #include <sys/mman.h> 40 #include <sys/syscall.h> /* for SYS_mmap */ 41 42 #include <algorithm> 43 #include <string> 44 #include <set> 45 #include <vector> 46 #include <string.h> 47 48 #define TESTALL(mask, var) (((mask) & (var)) == (mask)) 49 #define TESTANY(mask, var) (((mask) & (var)) != 0) 50 51 #define CHECK_IMPL(condition, file, line) \ 52 do { \ 53 if (!(condition)) { \ 54 dr_printf("Check failed: `%s`\nat %s:%d\n", #condition, file, line); \ 55 dr_abort(); \ 56 } \ 57 } while (0) // TODO: stacktrace 58 59 #define CHECK(condition) CHECK_IMPL(condition, __FILE__, __LINE__) 60 61 #define VERBOSITY 0 62 63 namespace { 64 65 class ModuleData { 66 public: 67 ModuleData(); 68 ModuleData(const module_data_t *info); 69 // Yes, we want default copy, assign, and dtor semantics. 70 71 public: 72 app_pc start_; 73 app_pc end_; 74 // Full path to the module. 75 std::string path_; 76 module_handle_t handle_; 77 bool should_instrument_; 78 bool executed_; 79 }; 80 81 std::string g_app_path; 82 83 int msan_retval_tls_offset; 84 int msan_param_tls_offset; 85 86 // A vector of loaded modules sorted by module bounds. We lookup the current PC 87 // in here from the bb event. This is better than an rb tree because the lookup 88 // is faster and the bb event occurs far more than the module load event. 89 std::vector<ModuleData> g_module_list; 90 91 ModuleData::ModuleData() 92 : start_(NULL), end_(NULL), path_(""), handle_(NULL), 93 should_instrument_(false), executed_(false) { 94 } 95 96 ModuleData::ModuleData(const module_data_t *info) 97 : start_(info->start), end_(info->end), path_(info->full_path), 98 handle_(info->handle), 99 // We'll check the black/white lists later and adjust this. 100 should_instrument_(true), executed_(false) { 101 } 102 103 int(*__msan_get_retval_tls_offset)(); 104 int(*__msan_get_param_tls_offset)(); 105 void (*__msan_unpoison)(void *base, size_t size); 106 bool (*__msan_is_in_loader)(); 107 108 static generic_func_t LookupCallback(module_data_t *app, const char *name) { 109 generic_func_t callback = dr_get_proc_address(app->handle, name); 110 if (callback == NULL) { 111 dr_printf("Couldn't find `%s` in %s\n", name, app->full_path); 112 CHECK(callback); 113 } 114 return callback; 115 } 116 117 void InitializeMSanCallbacks() { 118 module_data_t *app = dr_lookup_module_by_name(dr_get_application_name()); 119 if (!app) { 120 dr_printf("%s - oops, dr_lookup_module_by_name failed!\n", 121 dr_get_application_name()); 122 CHECK(app); 123 } 124 g_app_path = app->full_path; 125 126 __msan_get_retval_tls_offset = (int (*)()) 127 LookupCallback(app, "__msan_get_retval_tls_offset"); 128 __msan_get_param_tls_offset = (int (*)()) 129 LookupCallback(app, "__msan_get_param_tls_offset"); 130 __msan_unpoison = (void(*)(void *, size_t)) 131 LookupCallback(app, "__msan_unpoison"); 132 __msan_is_in_loader = (bool (*)()) 133 LookupCallback(app, "__msan_is_in_loader"); 134 135 dr_free_module_data(app); 136 } 137 138 // FIXME: Handle absolute addresses and PC-relative addresses. 139 // FIXME: Handle TLS accesses via FS or GS. DR assumes all other segments have 140 // a zero base anyway. 141 bool OperandIsInteresting(opnd_t opnd) { 142 return (opnd_is_base_disp(opnd) && opnd_get_segment(opnd) != DR_SEG_FS && 143 opnd_get_segment(opnd) != DR_SEG_GS); 144 } 145 146 bool WantToInstrument(instr_t *instr) { 147 // TODO: skip push instructions? 148 switch (instr_get_opcode(instr)) { 149 // FIXME: support the instructions excluded below: 150 case OP_rep_cmps: 151 // f3 a6 rep cmps %ds:(%rsi) %es:(%rdi) %rsi %rdi %rcx -> %rsi %rdi %rcx 152 return false; 153 } 154 155 // Labels appear due to drutil_expand_rep_string() 156 if (instr_is_label(instr)) 157 return false; 158 159 CHECK(instr_ok_to_mangle(instr) == true); 160 161 if (instr_writes_memory(instr)) { 162 for (int d = 0; d < instr_num_dsts(instr); d++) { 163 opnd_t op = instr_get_dst(instr, d); 164 if (OperandIsInteresting(op)) 165 return true; 166 } 167 } 168 169 return false; 170 } 171 172 #define PRE(at, what) instrlist_meta_preinsert(bb, at, INSTR_CREATE_##what); 173 #define PREF(at, what) instrlist_meta_preinsert(bb, at, what); 174 175 void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op, 176 bool is_write) { 177 bool need_to_restore_eflags = false; 178 uint flags = instr_get_arith_flags(instr); 179 // TODO: do something smarter with flags and spills in general? 180 // For example, spill them only once for a sequence of instrumented 181 // instructions that don't change/read flags. 182 183 if (!TESTALL(EFLAGS_WRITE_6, flags) || TESTANY(EFLAGS_READ_6, flags)) { 184 if (VERBOSITY > 1) 185 dr_printf("Spilling eflags...\n"); 186 need_to_restore_eflags = true; 187 // TODO: Maybe sometimes don't need to 'seto'. 188 // TODO: Maybe sometimes don't want to spill XAX here? 189 // TODO: No need to spill XAX here if XAX is not used in the BB. 190 dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 191 dr_save_arith_flags_to_xax(drcontext, bb, instr); 192 dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_3); 193 dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 194 } 195 196 #if 0 197 dr_printf("==DRMSAN== DEBUG: %d %d %d %d %d %d\n", 198 opnd_is_memory_reference(op), opnd_is_base_disp(op), 199 opnd_is_base_disp(op) ? opnd_get_index(op) : -1, 200 opnd_is_far_memory_reference(op), opnd_is_reg_pointer_sized(op), 201 opnd_is_base_disp(op) ? opnd_get_disp(op) : -1); 202 #endif 203 204 reg_id_t R1; 205 bool address_in_R1 = false; 206 if (opnd_is_base_disp(op) && opnd_get_index(op) == DR_REG_NULL && 207 opnd_get_disp(op) == 0) { 208 // If this is a simple access with no offset or index, we can just use the 209 // base for R1. 210 address_in_R1 = true; 211 R1 = opnd_get_base(op); 212 } else { 213 // Otherwise, we need to compute the addr into R1. 214 // TODO: reuse some spare register? e.g. r15 on x64 215 // TODO: might be used as a non-mem-ref register? 216 R1 = DR_REG_XAX; 217 } 218 CHECK(reg_is_pointer_sized(R1)); // otherwise R2 may be wrong. 219 220 // Pick R2 that's not R1 or used by the operand. It's OK if the instr uses 221 // R2 elsewhere, since we'll restore it before instr. 222 reg_id_t GPR_TO_USE_FOR_R2[] = { 223 DR_REG_XAX, DR_REG_XBX, DR_REG_XCX, DR_REG_XDX 224 // Don't forget to update the +4 below if you add anything else! 225 }; 226 std::set<reg_id_t> unused_registers(GPR_TO_USE_FOR_R2, GPR_TO_USE_FOR_R2 + 4); 227 unused_registers.erase(R1); 228 for (int j = 0; j < opnd_num_regs_used(op); j++) { 229 unused_registers.erase(opnd_get_reg_used(op, j)); 230 } 231 232 CHECK(unused_registers.size() > 0); 233 reg_id_t R2 = *unused_registers.begin(); 234 CHECK(R1 != R2); 235 236 // Save the current values of R1 and R2. 237 dr_save_reg(drcontext, bb, instr, R1, SPILL_SLOT_1); 238 // TODO: Something smarter than spilling a "fixed" register R2? 239 dr_save_reg(drcontext, bb, instr, R2, SPILL_SLOT_2); 240 241 if (!address_in_R1) 242 CHECK(drutil_insert_get_mem_addr(drcontext, bb, instr, op, R1, R2)); 243 PRE(instr, mov_imm(drcontext, opnd_create_reg(R2), 244 OPND_CREATE_INT64(0xffffbfffffffffff))); 245 PRE(instr, and(drcontext, opnd_create_reg(R1), opnd_create_reg(R2))); 246 // There is no mov_st of a 64-bit immediate, so... 247 opnd_size_t op_size = opnd_get_size(op); 248 CHECK(op_size != OPSZ_NA); 249 uint access_size = opnd_size_in_bytes(op_size); 250 if (access_size <= 4) { 251 PRE(instr, 252 mov_st(drcontext, opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size), 253 opnd_create_immed_int((ptr_int_t) 0, op_size))); 254 } else { 255 // FIXME: tail? 256 for (uint ofs = 0; ofs < access_size; ofs += 4) { 257 PRE(instr, 258 mov_st(drcontext, OPND_CREATE_MEM32(R1, ofs), OPND_CREATE_INT32(0))); 259 } 260 } 261 262 // Restore the registers and flags. 263 dr_restore_reg(drcontext, bb, instr, R1, SPILL_SLOT_1); 264 dr_restore_reg(drcontext, bb, instr, R2, SPILL_SLOT_2); 265 266 if (need_to_restore_eflags) { 267 if (VERBOSITY > 1) 268 dr_printf("Restoring eflags\n"); 269 // TODO: Check if it's reverse to the dr_restore_reg above and optimize. 270 dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 271 dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_3); 272 dr_restore_arith_flags_from_xax(drcontext, bb, instr); 273 dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 274 } 275 276 // The original instruction is left untouched. The above instrumentation is just 277 // a prefix. 278 } 279 280 void InstrumentReturn(void *drcontext, instrlist_t *bb, instr_t *instr) { 281 dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 282 283 // Clobbers nothing except xax. 284 bool res = 285 dr_insert_get_seg_base(drcontext, bb, instr, DR_SEG_FS, DR_REG_XAX); 286 CHECK(res); 287 288 // TODO: unpoison more bytes? 289 PRE(instr, 290 mov_st(drcontext, OPND_CREATE_MEM64(DR_REG_XAX, msan_retval_tls_offset), 291 OPND_CREATE_INT32(0))); 292 293 dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 294 295 // The original instruction is left untouched. The above instrumentation is just 296 // a prefix. 297 } 298 299 void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb, 300 instr_t *instr) { 301 dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 302 303 // Clobbers nothing except xax. 304 bool res = 305 dr_insert_get_seg_base(drcontext, bb, instr, DR_SEG_FS, DR_REG_XAX); 306 CHECK(res); 307 308 // TODO: unpoison more bytes? 309 for (int i = 0; i < 6; ++i) { 310 PRE(instr, 311 mov_st(drcontext, OPND_CREATE_MEMPTR(DR_REG_XAX, msan_param_tls_offset + 312 i * sizeof(void *)), 313 OPND_CREATE_INT32(0))); 314 } 315 316 dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1); 317 318 // The original instruction is left untouched. The above instrumentation is just 319 // a prefix. 320 } 321 322 // For use with binary search. Modules shouldn't overlap, so we shouldn't have 323 // to look at end_. If that can happen, we won't support such an application. 324 bool ModuleDataCompareStart(const ModuleData &left, const ModuleData &right) { 325 return left.start_ < right.start_; 326 } 327 328 // Look up the module containing PC. Should be relatively fast, as its called 329 // for each bb instrumentation. 330 ModuleData *LookupModuleByPC(app_pc pc) { 331 ModuleData fake_mod_data; 332 fake_mod_data.start_ = pc; 333 std::vector<ModuleData>::iterator it = 334 lower_bound(g_module_list.begin(), g_module_list.end(), fake_mod_data, 335 ModuleDataCompareStart); 336 // if (it == g_module_list.end()) 337 // return NULL; 338 if (it == g_module_list.end() || pc < it->start_) 339 --it; 340 CHECK(it->start_ <= pc); 341 if (pc >= it->end_) { 342 // We're past the end of this module. We shouldn't be in the next module, 343 // or lower_bound lied to us. 344 ++it; 345 CHECK(it == g_module_list.end() || pc < it->start_); 346 return NULL; 347 } 348 349 // OK, we found the module. 350 return &*it; 351 } 352 353 bool ShouldInstrumentNonModuleCode() { return true; } 354 355 bool ShouldInstrumentModule(ModuleData *mod_data) { 356 // TODO(rnk): Flags for blacklist would get wired in here. 357 generic_func_t p = 358 dr_get_proc_address(mod_data->handle_, "__msan_track_origins"); 359 return !p; 360 } 361 362 bool ShouldInstrumentPc(app_pc pc, ModuleData **pmod_data) { 363 ModuleData *mod_data = LookupModuleByPC(pc); 364 if (pmod_data) 365 *pmod_data = mod_data; 366 if (mod_data != NULL) { 367 // This module is on a blacklist. 368 if (!mod_data->should_instrument_) { 369 return false; 370 } 371 } else if (!ShouldInstrumentNonModuleCode()) { 372 return false; 373 } 374 return true; 375 } 376 377 // TODO(rnk): Make sure we instrument after __msan_init. 378 dr_emit_flags_t 379 event_basic_block_app2app(void *drcontext, void *tag, instrlist_t *bb, 380 bool for_trace, bool translating) { 381 app_pc pc = dr_fragment_app_pc(tag); 382 383 if (ShouldInstrumentPc(pc, NULL)) 384 CHECK(drutil_expand_rep_string(drcontext, bb)); 385 386 return DR_EMIT_PERSISTABLE; 387 } 388 389 dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, 390 bool for_trace, bool translating) { 391 app_pc pc = dr_fragment_app_pc(tag); 392 ModuleData *mod_data; 393 394 if (!ShouldInstrumentPc(pc, &mod_data)) 395 return DR_EMIT_PERSISTABLE; 396 397 if (VERBOSITY > 1) 398 dr_printf("============================================================\n"); 399 if (VERBOSITY > 0) { 400 std::string mod_path = (mod_data ? mod_data->path_ : "<no module, JITed?>"); 401 if (mod_data && !mod_data->executed_) { 402 mod_data->executed_ = true; // Nevermind this race. 403 dr_printf("Executing from new module: %s\n", mod_path.c_str()); 404 } 405 dr_printf("BB to be instrumented: %p [from %s]; translating = %s\n", pc, 406 mod_path.c_str(), translating ? "true" : "false"); 407 if (mod_data) { 408 // Match standard sanitizer trace format for free symbols. 409 // #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) 410 dr_printf(" #0 %p (%s+%p)\n", pc, mod_data->path_.c_str(), 411 pc - mod_data->start_); 412 } 413 } 414 if (VERBOSITY > 1) { 415 instrlist_disassemble(drcontext, pc, bb, STDOUT); 416 instr_t *instr; 417 for (instr = instrlist_first(bb); instr; instr = instr_get_next(instr)) { 418 dr_printf("opcode: %d\n", instr_get_opcode(instr)); 419 } 420 } 421 422 for (instr_t *i = instrlist_first(bb); i != NULL; i = instr_get_next(i)) { 423 int opcode = instr_get_opcode(i); 424 if (opcode == OP_ret || opcode == OP_ret_far) { 425 InstrumentReturn(drcontext, bb, i); 426 continue; 427 } 428 429 // These instructions hopefully cover all cases where control is transferred 430 // to a function in a different module (we only care about calls into 431 // compiler-instrumented modules). 432 // * call_ind is used for normal indirect calls. 433 // * jmp_ind is used for indirect tail calls, and calls through PLT (PLT 434 // stub includes a jump to an address from GOT). 435 if (opcode == OP_call_ind || opcode == OP_call_far_ind || 436 opcode == OP_jmp_ind || opcode == OP_jmp_far_ind) { 437 InstrumentIndirectBranch(drcontext, bb, i); 438 continue; 439 } 440 441 if (!WantToInstrument(i)) 442 continue; 443 444 if (VERBOSITY > 1) { 445 app_pc orig_pc = dr_fragment_app_pc(tag); 446 uint flags = instr_get_arith_flags(i); 447 dr_printf("+%d -> to be instrumented! [opcode=%d, flags = 0x%08X]\n", 448 instr_get_app_pc(i) - orig_pc, instr_get_opcode(i), flags); 449 } 450 451 if (instr_writes_memory(i)) { 452 // Instrument memory writes 453 // bool instrumented_anything = false; 454 for (int d = 0; d < instr_num_dsts(i); d++) { 455 opnd_t op = instr_get_dst(i, d); 456 if (!OperandIsInteresting(op)) 457 continue; 458 459 // CHECK(!instrumented_anything); 460 // instrumented_anything = true; 461 InstrumentMops(drcontext, bb, i, op, true); 462 break; // only instrumenting the first dst 463 } 464 } 465 } 466 467 // TODO: optimize away redundant restore-spill pairs? 468 469 if (VERBOSITY > 1) { 470 pc = dr_fragment_app_pc(tag); 471 dr_printf("\nFinished instrumenting dynamorio_basic_block(PC=" PFX ")\n", pc); 472 instrlist_disassemble(drcontext, pc, bb, STDOUT); 473 } 474 return DR_EMIT_PERSISTABLE; 475 } 476 477 void event_module_load(void *drcontext, const module_data_t *info, 478 bool loaded) { 479 // Insert the module into the list while maintaining the ordering. 480 ModuleData mod_data(info); 481 std::vector<ModuleData>::iterator it = 482 upper_bound(g_module_list.begin(), g_module_list.end(), mod_data, 483 ModuleDataCompareStart); 484 it = g_module_list.insert(it, mod_data); 485 // Check if we should instrument this module. 486 it->should_instrument_ = ShouldInstrumentModule(&*it); 487 dr_module_set_should_instrument(info->handle, it->should_instrument_); 488 489 if (VERBOSITY > 0) 490 dr_printf("==DRMSAN== Loaded module: %s [%p...%p], instrumentation is %s\n", 491 info->full_path, info->start, info->end, 492 it->should_instrument_ ? "on" : "off"); 493 } 494 495 void event_module_unload(void *drcontext, const module_data_t *info) { 496 if (VERBOSITY > 0) 497 dr_printf("==DRMSAN== Unloaded module: %s [%p...%p]\n", info->full_path, 498 info->start, info->end); 499 500 // Remove the module from the list. 501 ModuleData mod_data(info); 502 std::vector<ModuleData>::iterator it = 503 lower_bound(g_module_list.begin(), g_module_list.end(), mod_data, 504 ModuleDataCompareStart); 505 // It's a bug if we didn't actually find the module. 506 CHECK(it != g_module_list.end() && it->start_ == mod_data.start_ && 507 it->end_ == mod_data.end_ && it->path_ == mod_data.path_); 508 g_module_list.erase(it); 509 } 510 511 void event_exit() { 512 // Clean up so DR doesn't tell us we're leaking memory. 513 drsys_exit(); 514 drutil_exit(); 515 drmgr_exit(); 516 517 if (VERBOSITY > 0) 518 dr_printf("==DRMSAN== DONE\n"); 519 } 520 521 bool event_filter_syscall(void *drcontext, int sysnum) { 522 // FIXME: only intercept syscalls with memory effects. 523 return true; /* intercept everything */ 524 } 525 526 bool drsys_iter_memarg_cb(drsys_arg_t *arg, void *user_data) { 527 CHECK(arg->valid); 528 529 if (arg->pre) 530 return true; 531 if (!TESTANY(DRSYS_PARAM_OUT, arg->mode)) 532 return true; 533 534 size_t sz = arg->size; 535 536 if (sz > 0xFFFFFFFF) { 537 drmf_status_t res; 538 drsys_syscall_t *syscall = (drsys_syscall_t *)user_data; 539 const char *name; 540 res = drsys_syscall_name(syscall, &name); 541 CHECK(res == DRMF_SUCCESS); 542 543 dr_printf("SANITY: syscall '%s' arg %d writes %llu bytes memory?!" 544 " Clipping to %llu.\n", 545 name, arg->ordinal, (unsigned long long) sz, 546 (unsigned long long)(sz & 0xFFFFFFFF)); 547 } 548 549 if (VERBOSITY > 0) { 550 drmf_status_t res; 551 drsys_syscall_t *syscall = (drsys_syscall_t *)user_data; 552 const char *name; 553 res = drsys_syscall_name(syscall, &name); 554 dr_printf("drsyscall: syscall '%s' arg %d wrote range [%p, %p)\n", 555 name, arg->ordinal, arg->start_addr, 556 (char *)arg->start_addr + sz); 557 } 558 559 // We don't switch to the app context because __msan_unpoison() doesn't need 560 // TLS segments. 561 __msan_unpoison(arg->start_addr, sz); 562 563 return true; /* keep going */ 564 } 565 566 bool event_pre_syscall(void *drcontext, int sysnum) { 567 drsys_syscall_t *syscall; 568 drsys_sysnum_t sysnum_full; 569 bool known; 570 drsys_param_type_t ret_type; 571 drmf_status_t res; 572 const char *name; 573 574 res = drsys_cur_syscall(drcontext, &syscall); 575 CHECK(res == DRMF_SUCCESS); 576 577 res = drsys_syscall_number(syscall, &sysnum_full); 578 CHECK(res == DRMF_SUCCESS); 579 CHECK(sysnum == sysnum_full.number); 580 581 res = drsys_syscall_is_known(syscall, &known); 582 CHECK(res == DRMF_SUCCESS); 583 584 res = drsys_syscall_name(syscall, &name); 585 CHECK(res == DRMF_SUCCESS); 586 587 res = drsys_syscall_return_type(syscall, &ret_type); 588 CHECK(res == DRMF_SUCCESS); 589 CHECK(ret_type != DRSYS_TYPE_INVALID); 590 CHECK(!known || ret_type != DRSYS_TYPE_UNKNOWN); 591 592 res = drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, NULL); 593 CHECK(res == DRMF_SUCCESS); 594 595 return true; 596 } 597 598 static bool IsInLoader(void *drcontext) { 599 // TODO: This segment swap is inefficient. DR should just let us query the 600 // app segment base, which it has. Alternatively, if we disable 601 // -mangle_app_seg, then we won't need the swap. 602 bool need_swap = !dr_using_app_state(drcontext); 603 if (need_swap) 604 dr_switch_to_app_state(drcontext); 605 bool is_in_loader = __msan_is_in_loader(); 606 if (need_swap) 607 dr_switch_to_dr_state(drcontext); 608 return is_in_loader; 609 } 610 611 void event_post_syscall(void *drcontext, int sysnum) { 612 drsys_syscall_t *syscall; 613 drsys_sysnum_t sysnum_full; 614 bool success = false; 615 drmf_status_t res; 616 617 res = drsys_cur_syscall(drcontext, &syscall); 618 CHECK(res == DRMF_SUCCESS); 619 620 res = drsys_syscall_number(syscall, &sysnum_full); 621 CHECK(res == DRMF_SUCCESS); 622 CHECK(sysnum == sysnum_full.number); 623 624 res = drsys_syscall_succeeded(syscall, dr_syscall_get_result(drcontext), 625 &success); 626 CHECK(res == DRMF_SUCCESS); 627 628 if (success) { 629 res = 630 drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, (void *)syscall); 631 CHECK(res == DRMF_SUCCESS); 632 } 633 634 // Our normal mmap interceptor can't intercept calls from the loader itself. 635 // This means we don't clear the shadow for calls to dlopen. For now, we 636 // solve this by intercepting mmap from ld.so here, but ideally we'd have a 637 // solution that doesn't rely on msandr. 638 // 639 // Be careful not to intercept maps done by the msan rtl. Otherwise we end up 640 // unpoisoning vast regions of memory and OOMing. 641 // TODO: __msan_unpoison() could "flush" large regions of memory like tsan 642 // does instead of doing a large memset. However, we need the memory to be 643 // zeroed, where as tsan does not, so plain madvise is not enough. 644 if (success && (sysnum == SYS_mmap IF_NOT_X64(|| sysnum == SYS_mmap2))) { 645 if (IsInLoader(drcontext)) { 646 app_pc base = (app_pc)dr_syscall_get_result(drcontext); 647 ptr_uint_t size; 648 drmf_status_t res = drsys_pre_syscall_arg(drcontext, 1, &size); 649 CHECK(res == DRMF_SUCCESS); 650 if (VERBOSITY > 0) 651 dr_printf("unpoisoning for dlopen: [%p-%p]\n", base, base + size); 652 // We don't switch to the app context because __msan_unpoison() doesn't 653 // need TLS segments. 654 __msan_unpoison(base, size); 655 } 656 } 657 } 658 659 } // namespace 660 661 DR_EXPORT void dr_init(client_id_t id) { 662 drmf_status_t res; 663 664 drmgr_init(); 665 drutil_init(); 666 667 std::string app_name = dr_get_application_name(); 668 // This blacklist will still run these apps through DR's code cache. On the 669 // other hand, we are able to follow children of these apps. 670 // FIXME: Once DR has detach, we could just detach here. Alternatively, 671 // if DR had a fork or exec hook to let us decide there, that would be nice. 672 // FIXME: make the blacklist cmd-adjustable. 673 if (app_name == "python" || app_name == "python2.7" || app_name == "bash" || 674 app_name == "sh" || app_name == "true" || app_name == "exit" || 675 app_name == "yes" || app_name == "echo") 676 return; 677 678 drsys_options_t ops; 679 memset(&ops, 0, sizeof(ops)); 680 ops.struct_size = sizeof(ops); 681 ops.analyze_unknown_syscalls = false; 682 683 res = drsys_init(id, &ops); 684 CHECK(res == DRMF_SUCCESS); 685 686 dr_register_filter_syscall_event(event_filter_syscall); 687 drmgr_register_pre_syscall_event(event_pre_syscall); 688 drmgr_register_post_syscall_event(event_post_syscall); 689 res = drsys_filter_all_syscalls(); 690 CHECK(res == DRMF_SUCCESS); 691 692 InitializeMSanCallbacks(); 693 694 // FIXME: the shadow is initialized earlier when DR calls one of our wrapper 695 // functions. This may change one day. 696 // TODO: make this more robust. 697 698 void *drcontext = dr_get_current_drcontext(); 699 700 dr_switch_to_app_state(drcontext); 701 msan_retval_tls_offset = __msan_get_retval_tls_offset(); 702 msan_param_tls_offset = __msan_get_param_tls_offset(); 703 dr_switch_to_dr_state(drcontext); 704 if (VERBOSITY > 0) { 705 dr_printf("__msan_retval_tls offset: %d\n", msan_retval_tls_offset); 706 dr_printf("__msan_param_tls offset: %d\n", msan_param_tls_offset); 707 } 708 709 // Standard DR events. 710 dr_register_exit_event(event_exit); 711 712 drmgr_priority_t priority = { 713 sizeof(priority), /* size of struct */ 714 "msandr", /* name of our operation */ 715 NULL, /* optional name of operation we should precede */ 716 NULL, /* optional name of operation we should follow */ 717 0 718 }; /* numeric priority */ 719 720 drmgr_register_bb_app2app_event(event_basic_block_app2app, &priority); 721 drmgr_register_bb_instru2instru_event(event_basic_block, &priority); 722 drmgr_register_module_load_event(event_module_load); 723 drmgr_register_module_unload_event(event_module_unload); 724 if (VERBOSITY > 0) 725 dr_printf("==MSANDR== Starting!\n"); 726 } 727