[sanitizer] Implement MapDynamicShadowAndAliases.

The function works like MapDynamicShadow, except that it creates aliased
memory to the right of the shadow.  The main use case is for HWASan
aliasing mode, which gets fast IsAlias() checks by exploiting the fact
that the upper bits of the shadow base and aliased memory match.

Reviewed By: vitalybuka, eugenis

Differential Revision: https://reviews.llvm.org/D98369
This commit is contained in:
Matt Morehouse 2021-03-23 11:21:08 -07:00
parent f499b932bf
commit f85002d22c
7 changed files with 96 additions and 0 deletions

View File

@ -135,6 +135,15 @@ void UnmapFromTo(uptr from, uptr to);
uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
uptr min_shadow_base_alignment, uptr &high_mem_end);
// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
// Reserves 2*S bytes of address space to the right of the returned address and
// ring_buffer_size bytes to the left. The returned address is aligned to 2*S.
// Also creates num_aliases regions of accessible memory starting at offset S
// from the returned address. Each region has size alias_size and is backed by
// the same physical memory.
uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
uptr num_aliases, uptr ring_buffer_size);
// Reserve memory range [beg, end]. If madvise_shadow is true then apply
// madvise (e.g. hugepages, core dumping) requested by options.
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,

View File

@ -183,6 +183,12 @@ uptr internal_munmap(void *addr, uptr length) {
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
}
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
void *new_address) {
return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
new_size, flags, (uptr)new_address);
}
int internal_mprotect(void *addr, uptr length, int prot) {
return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
}

View File

@ -36,6 +36,7 @@
#include <link.h>
#include <pthread.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <syslog.h>
@ -915,6 +916,60 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
return shadow_start;
}
static uptr MmapSharedNoReserve(uptr addr, uptr size) {
return internal_mmap(
reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
}
static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
uptr alias_size) {
return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
MREMAP_MAYMOVE | MREMAP_FIXED,
reinterpret_cast<void *>(alias_addr));
}
static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
uptr total_size = alias_size * num_aliases;
uptr mapped = MmapSharedNoReserve(start_addr, total_size);
CHECK_EQ(mapped, start_addr);
for (uptr i = 1; i < num_aliases; ++i) {
uptr alias_addr = start_addr + i * alias_size;
CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
}
}
uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
uptr num_aliases, uptr ring_buffer_size) {
CHECK_EQ(alias_size & (alias_size - 1), 0);
CHECK_EQ(num_aliases & (num_aliases - 1), 0);
CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
const uptr granularity = GetMmapGranularity();
shadow_size = RoundUpTo(shadow_size, granularity);
CHECK_EQ(shadow_size & (shadow_size - 1), 0);
const uptr alias_region_size = alias_size * num_aliases;
const uptr alignment =
2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
const uptr left_padding = ring_buffer_size;
const uptr right_size = alignment;
const uptr map_size = left_padding + 2 * alignment;
const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
CHECK_NE(map_start, static_cast<uptr>(-1));
const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
UnmapFromTo(map_start, right_start - left_padding);
UnmapFromTo(right_start + right_size, map_start + map_size);
CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
return right_start;
}
void InitializePlatformCommonFlags(CommonFlags *cf) {
#if SANITIZER_ANDROID
if (&__libc_get_static_tls_bounds == nullptr)

View File

@ -142,6 +142,12 @@ uptr internal_munmap(void *addr, uptr length) {
return munmap(addr, length);
}
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
void *new_address) {
CHECK(false && "internal_mremap is unimplemented on Mac");
return 0;
}
int internal_mprotect(void *addr, uptr length, int prot) {
return mprotect(addr, length, prot);
}
@ -1252,6 +1258,12 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
return shadow_start;
}
uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
uptr num_aliases, uptr ring_buffer_size) {
CHECK(false && "HWASan aliasing is unimplemented on Mac");
return 0;
}
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
uptr *largest_gap_found,
uptr *max_occupied_addr) {

View File

@ -105,6 +105,12 @@ uptr internal_munmap(void *addr, uptr length) {
return _REAL(munmap, addr, length);
}
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
void *new_address) {
CHECK(false && "internal_mremap is unimplemented on NetBSD");
return 0;
}
int internal_mprotect(void *addr, uptr length, int prot) {
DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
return _REAL(mprotect, addr, length, prot);

View File

@ -40,6 +40,8 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset);
uptr internal_munmap(void *addr, uptr length);
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
void *new_address);
int internal_mprotect(void *addr, uptr length, int prot);
int internal_madvise(uptr addr, uptr length, int advice);

View File

@ -390,6 +390,12 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
return 0;
}
uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
uptr num_aliases, uptr ring_buffer_size) {
CHECK(false && "HWASan aliasing is unimplemented on Windows");
return 0;
}
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
MEMORY_BASIC_INFORMATION mbi;
CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));