diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h --- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h +++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h @@ -28,6 +28,9 @@ // otherwise). class GuardedPoolAllocator { public: + // Name of the GWP-ASan mapping that for `Metadata`. + static constexpr const char *kGwpAsanMetadataName = "GWP-ASan Metadata"; + static constexpr uint64_t kInvalidThreadID = UINT64_MAX; enum class Error { @@ -154,6 +157,14 @@ static uint64_t getThreadID(); private: + // Name of actively-occupied slot mappings. + static constexpr const char *kGwpAsanAliveSlotName = "GWP-ASan Alive Slot"; + // Name of the guard pages. This includes all slots that are not actively in + // use (i.e. were never used, or have been free()'d).) + static constexpr const char *kGwpAsanGuardPageName = "GWP-ASan Guard Page"; + // Name of the mapping for `FreeSlots`. + static constexpr const char *kGwpAsanFreeSlotsName = "GWP-ASan Metadata"; + static constexpr size_t kInvalidSlotID = SIZE_MAX; // These functions anonymously map memory or change the permissions of mapped @@ -162,11 +173,13 @@ // return on error, instead electing to kill the calling process on failure. // Note that memory is initially mapped inaccessible. In order for RW // mappings, call mapMemory() followed by markReadWrite() on the returned - // pointer. - void *mapMemory(size_t Size) const; - void unmapMemory(void *Addr, size_t Size) const; - void markReadWrite(void *Ptr, size_t Size) const; - void markInaccessible(void *Ptr, size_t Size) const; + // pointer. Each mapping is named on platforms that support it, primarily + // Android. This name must be a statically allocated string, as the Android + // kernel uses the string pointer directly. + void *mapMemory(size_t Size, const char *Name) const; + void unmapMemory(void *Ptr, size_t Size, const char *Name) const; + void markReadWrite(void *Ptr, size_t Size, const char *Name) const; + void markInaccessible(void *Ptr, size_t Size, const char *Name) const; // Get the page size from the platform-specific implementation. Only needs to // be called once, and the result should be cached in PageSize in this class. diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp --- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp +++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp @@ -144,16 +144,18 @@ size_t PoolBytesRequired = PageSize * (1 + MaxSimultaneousAllocations) + MaxSimultaneousAllocations * maximumAllocationSize(); - void *GuardedPoolMemory = mapMemory(PoolBytesRequired); + void *GuardedPoolMemory = mapMemory(PoolBytesRequired, kGwpAsanGuardPageName); size_t BytesRequired = MaxSimultaneousAllocations * sizeof(*Metadata); - Metadata = reinterpret_cast(mapMemory(BytesRequired)); - markReadWrite(Metadata, BytesRequired); + Metadata = reinterpret_cast( + mapMemory(BytesRequired, kGwpAsanMetadataName)); + markReadWrite(Metadata, BytesRequired, kGwpAsanMetadataName); // Allocate memory and set up the free pages queue. BytesRequired = MaxSimultaneousAllocations * sizeof(*FreeSlots); - FreeSlots = reinterpret_cast(mapMemory(BytesRequired)); - markReadWrite(FreeSlots, BytesRequired); + FreeSlots = reinterpret_cast( + mapMemory(BytesRequired, kGwpAsanFreeSlotsName)); + markReadWrite(FreeSlots, BytesRequired, kGwpAsanFreeSlotsName); // Multiply the sample rate by 2 to give a good, fast approximation for (1 / // SampleRate) chance of sampling. @@ -183,16 +185,18 @@ void GuardedPoolAllocator::uninitTestOnly() { if (GuardedPagePool) { unmapMemory(reinterpret_cast(GuardedPagePool), - GuardedPagePoolEnd - GuardedPagePool); + GuardedPagePoolEnd - GuardedPagePool, kGwpAsanGuardPageName); GuardedPagePool = 0; GuardedPagePoolEnd = 0; } if (Metadata) { - unmapMemory(Metadata, MaxSimultaneousAllocations * sizeof(*Metadata)); + unmapMemory(Metadata, MaxSimultaneousAllocations * sizeof(*Metadata), + kGwpAsanMetadataName); Metadata = nullptr; } if (FreeSlots) { - unmapMemory(FreeSlots, MaxSimultaneousAllocations * sizeof(*FreeSlots)); + unmapMemory(FreeSlots, MaxSimultaneousAllocations * sizeof(*FreeSlots), + kGwpAsanFreeSlotsName); FreeSlots = nullptr; } uninstallSignalHandlers(); @@ -228,7 +232,8 @@ // If a slot is multiple pages in size, and the allocation takes up a single // page, we can improve overflow detection by leaving the unused pages as // unmapped. - markReadWrite(reinterpret_cast(getPageAddr(Ptr)), Size); + markReadWrite(reinterpret_cast(getPageAddr(Ptr)), Size, + kGwpAsanAliveSlotName); Meta->RecordAllocation(Ptr, Size, Backtrace); @@ -260,8 +265,8 @@ Meta->RecordDeallocation(Backtrace); } - markInaccessible(reinterpret_cast(SlotStart), - maximumAllocationSize()); + markInaccessible(reinterpret_cast(SlotStart), maximumAllocationSize(), + kGwpAsanGuardPageName); // And finally, lock again to release the slot back into the pool. ScopedLock L(PoolMutex); diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp @@ -17,9 +17,22 @@ #include #include -namespace gwp_asan { +#ifdef ANDROID +#include +#define PR_SET_VMA 0x53564d41 +#define PR_SET_VMA_ANON_NAME 0 +#endif // ANDROID + +void MaybeSetMappingName(void *Mapping, size_t Size, const char *Name) { +#ifdef ANDROID + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Mapping, Size, Name); +#endif // ANDROID + // Anonymous mapping names are only supported on Android. + return; +} -void *GuardedPoolAllocator::mapMemory(size_t Size) const { +namespace gwp_asan { +void *GuardedPoolAllocator::mapMemory(size_t Size, const char *Name) const { void *Ptr = mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); @@ -28,29 +41,35 @@ Printf(" mmap(nullptr, %zu, ...) failed.\n", Size); exit(EXIT_FAILURE); } + MaybeSetMappingName(Ptr, Size, Name); return Ptr; } -void GuardedPoolAllocator::unmapMemory(void *Addr, size_t Size) const { - int Res = munmap(Addr, Size); +void GuardedPoolAllocator::unmapMemory(void *Ptr, size_t Size, + const char *Name) const { + int Res = munmap(Ptr, Size); if (Res != 0) { Printf("Failed to unmap guarded pool allocator memory, errno: %d\n", errno); - Printf(" unmmap(%p, %zu, ...) failed.\n", Addr, Size); + Printf(" unmmap(%p, %zu, ...) failed.\n", Ptr, Size); exit(EXIT_FAILURE); } + MaybeSetMappingName(Ptr, Size, Name); } -void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size) const { +void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size, + const char *Name) const { if (mprotect(Ptr, Size, PROT_READ | PROT_WRITE) != 0) { Printf("Failed to set guarded pool allocator memory at as RW, errno: %d\n", errno); Printf(" mprotect(%p, %zu, RW) failed.\n", Ptr, Size); exit(EXIT_FAILURE); } + MaybeSetMappingName(Ptr, Size, Name); } -void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size) const { +void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size, + const char *Name) const { // mmap() a PROT_NONE page over the address to release it to the system, if // we used mprotect() here the system would count pages in the quarantine // against the RSS. @@ -62,6 +81,7 @@ Printf(" mmap(%p, %zu, NONE, ...) failed.\n", Ptr, Size); exit(EXIT_FAILURE); } + MaybeSetMappingName(Ptr, Size, Name); } size_t GuardedPoolAllocator::getPlatformPageSize() {