diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-03-11 18:07:42 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-03-11 18:07:42 +0000 |
commit | 0f92deb81207c80481ff0257fbaba640fe669633 (patch) | |
tree | d607657bc3c761a28ef7798195339f04fc8d837b /lib/msan/msan_linux.cc | |
parent | ce700979f644c790c2d9d80f5cc2a1ada0380284 (diff) |
[msan] intercept dlopen and clear shadow for it
Summary:
The loader does not call mmap() through the PLT because it has to
bootstrap the process before libc is present. Hooking dlopen() isn't
enough either because the loader runs module initializers before
returning, and they could run arbitrary msan instrumented code.
If msandr is present, then we can intercept the mmaps from dlopen at the
syscall layer and clear the shadow there. If msandr is missing, we
clear the shadow after dlopen() and hope any initializers are trivial.
Reviewers: eugenis
CC: kcc, llvm-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D509
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@176818 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/msan/msan_linux.cc')
-rw-r--r-- | lib/msan/msan_linux.cc | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc index 0b08b7def..64aa35b0b 100644 --- a/lib/msan/msan_linux.cc +++ b/lib/msan/msan_linux.cc @@ -16,6 +16,9 @@ #include "msan.h" +#include <algorithm> +#include <elf.h> +#include <link.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> @@ -87,6 +90,42 @@ static void MsanAtExit(void) { void InstallAtExitHandler() { atexit(MsanAtExit); } + +void UnpoisonMappedDSO(link_map *map) { + typedef ElfW(Phdr) Elf_Phdr; + typedef ElfW(Ehdr) Elf_Ehdr; + char *base = (char *)map->l_addr; + Elf_Ehdr *ehdr = (Elf_Ehdr *)base; + char *phdrs = base + ehdr->e_phoff; + char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; + + // Find the segment with the minimum base so we can "relocate" the p_vaddr + // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC + // objects have a non-zero base. + uptr preferred_base = ~0ULL; + for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { + Elf_Phdr *phdr = (Elf_Phdr *)iter; + if (phdr->p_type == PT_LOAD) + preferred_base = std::min(preferred_base, (uptr)phdr->p_vaddr); + } + + // Compute the delta from the real base to get a relocation delta. + ptrdiff_t delta = (uptr)base - preferred_base; + // Now we can figure out what the loader really mapped. + for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { + Elf_Phdr *phdr = (Elf_Phdr *)iter; + if (phdr->p_type == PT_LOAD) { + uptr seg_start = phdr->p_vaddr + delta; + uptr seg_end = seg_start + phdr->p_memsz; + // None of these values are aligned. We consider the ragged edges of the + // load command as defined, since they are mapped from the file. + seg_start = RoundDownTo(seg_start, GetPageSizeCached()); + seg_end = RoundUpTo(seg_end, GetPageSizeCached()); + __msan_unpoison((void *)seg_start, seg_end - seg_start); + } + } +} + } // namespace __msan #endif // __linux__ |