diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -23,6 +23,7 @@ #include "asan_suppressions.h" #include "asan_thread.h" #include "lsan/lsan_common.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" @@ -146,6 +147,48 @@ *begin = *end = 0; \ } +template +static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, + int prot, int flags, int fd, OFF64_T offset) { + void *res = real_mmap(addr, length, prot, flags, fd, offset); + if (length && res != (void *)-1) { + const uptr beg = reinterpret_cast(res); + DCHECK(IsAligned(beg, GetPageSize())); + SIZE_T rounded_length = RoundUpTo(length, GetPageSize()); + // Only unpoison shadow if it's an ASAN managed address. + if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1)) + PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 0); + } + return res; +} + +template +static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) { + // We should not tag if munmap fail, but it's to late to tag after + // real_munmap, as the pages could be mmaped by another thread. + const uptr beg = reinterpret_cast(addr); + if (length && IsAligned(beg, GetPageSize())) { + SIZE_T rounded_length = RoundUpTo(length, GetPageSize()); + // Protect from unmapping the shadow. + if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1)) + PoisonShadow(beg, rounded_length, 0); + } + return real_munmap(addr, length); +} + +# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \ + fd, offset) \ + do { \ + (void)(ctx); \ + return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \ + } while (false) + +# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \ + do { \ + (void)(ctx); \ + return munmap_interceptor(REAL(munmap), addr, sz); \ + } while (false) + #if CAN_SANITIZE_LEAKS #define COMMON_INTERCEPTOR_STRERROR() \ __lsan::ScopedInterceptorDisabler disabler diff --git a/compiler-rt/test/asan/TestCases/mapped_mem_interceptors.c b/compiler-rt/test/asan/TestCases/mapped_mem_interceptors.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/mapped_mem_interceptors.c @@ -0,0 +1,45 @@ +// Test for mmap/munmap interceptors. +// RUN: %clang_asan %s -o %t +// RUN: %run %t 2>&1 + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + int size = 4096; + int val = 42; + + // Get any mmaped pointer. + void *r = + mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + assert(r != MAP_FAILED); + + // Make sure the memory is unpoisoned. + if (__asan_region_is_poisoned(r, size) != 0) { + fprintf(stderr, "Memory returned by mmap should be unpoisoned.\n"); + abort(); + } + + // First munmmap and then mmap the same pointer using MAP_FIXED. + __asan_poison_memory_region(r, size); + munmap(r, size); + if (__asan_region_is_poisoned(r, size) != 0) { + fprintf(stderr, "Shadow memory was not cleaned by munmap.\n"); + abort(); + } + __asan_poison_memory_region(r, size); + void *p = mmap(r, size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); + assert(r == p); + + // Make sure the memory is unpoisoned. + if (__asan_region_is_poisoned(r, size) != 0) { + fprintf(stderr, "Memory returned by mmap should be unpoisoned.\n"); + abort(); + } + + return 0; +}