[compiler-rt] Make interceptors fail earlier (PR #171295)
Honey Goyal via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 9 00:28:51 PST 2025
https://github.com/honeygoyal created https://github.com/llvm/llvm-project/pull/171295
If the address range is not covered by shadow memory, make interceptors like mmap fail earlier.
>From 7119e113a203d1b74a66c4d045443272df273f1f Mon Sep 17 00:00:00 2001
From: Honey Goyal <honey.goyal3 at ibm.com>
Date: Tue, 9 Dec 2025 08:34:04 +0000
Subject: [PATCH] Implement mmap fail earlier
---
compiler-rt/lib/asan/asan_errors.cpp | 54 ++++++++
compiler-rt/lib/asan/asan_errors.h | 66 ++++++++++
compiler-rt/lib/asan/asan_interceptors.cpp | 116 ++++++++++++++----
compiler-rt/lib/asan/asan_report.cpp | 30 +++++
compiler-rt/lib/asan/asan_report.h | 5 +
.../test/asan/TestCases/asan_mmap_oob_aix.cpp | 17 +++
6 files changed, 267 insertions(+), 21 deletions(-)
create mode 100644 compiler-rt/test/asan/TestCases/asan_mmap_oob_aix.cpp
diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp
index 99d6bdac3d720..6f37e8a995865 100644
--- a/compiler-rt/lib/asan/asan_errors.cpp
+++ b/compiler-rt/lib/asan/asan_errors.cpp
@@ -265,6 +265,60 @@ void ErrorAllocationSizeTooBig::Print() {
PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
+void ErrorMmapAddrOverflow::Print() {
+ Decorator d;
+ Printf("%s", d.Error());
+ Report("ERROR: AddressSanitizer: mmap requested memory range (0x%zx + 0x%zx) "
+ "causes address overflow\n", start, length);
+ Printf("%s", d.Default());
+ stack->Print();
+ PrintHintAllocatorCannotReturnNull();
+ ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
+void ErrorMmapShadowOverlap::Print() {
+ Decorator d;
+ Printf("%s", d.Error());
+ Report("ERROR: AddressSanitizer: mmap requested memory range 0x%zx-0x%zx "
+ "overlaps with ASan shadow memory\n", start, end);
+ Printf("%s", d.Default());
+ stack->Print();
+ PrintHintAllocatorCannotReturnNull();
+ ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
+void ErrorMmapOutsideRange::Print() {
+ Decorator d;
+ Printf("%s", d.Error());
+ Report("ERROR: AddressSanitizer: mmap requested memory range 0x%zx-0x%zx is "
+ "outside ASan's instrumentable application memory range\n", start, end);
+ Printf("%s", d.Default());
+ stack->Print();
+ PrintHintAllocatorCannotReturnNull();
+ ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
+void ErrorMunmapShadowOverlap::Print() {
+ Decorator d;
+ Printf("%s", d.Error());
+ Report("ERROR: AddressSanitizer: munmap requested memory range 0x%zx-0x%zx "
+ "overlaps with ASan shadow memory\n", start, end);
+ Printf("%s", d.Default());
+ stack->Print();
+ PrintHintAllocatorCannotReturnNull();
+ ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
+void ErrorMunmapOutsideRange::Print() {
+ Decorator d;
+ Printf("%s", d.Error());
+ Report("ERROR: AddressSanitizer: munmap requested memory range 0x%zx-0x%zx is "
+ "outside ASan's instrumentable application memory range\n", start, end);
+ Printf("%s", d.Default());
+ stack->Print();
+ PrintHintAllocatorCannotReturnNull();
+ ReportErrorSummary(scariness.GetDescription(), stack);
+}
void ErrorRssLimitExceeded::Print() {
Decorator d;
diff --git a/compiler-rt/lib/asan/asan_errors.h b/compiler-rt/lib/asan/asan_errors.h
index f339b35d2a764..13e66865a6eb9 100644
--- a/compiler-rt/lib/asan/asan_errors.h
+++ b/compiler-rt/lib/asan/asan_errors.h
@@ -249,6 +249,67 @@ struct ErrorAllocationSizeTooBig : ErrorBase {
void Print();
};
+struct ErrorMmapAddrOverflow : ErrorBase {
+ const BufferedStackTrace *stack;
+ uptr start;
+ uptr length;
+ ErrorMmapAddrOverflow() = default;
+ ErrorMmapAddrOverflow(u32 tid, BufferedStackTrace *stack_, uptr start_, uptr len)
+ : ErrorBase(tid, 10, "bad-mmap-overflow"),
+ stack(stack_),
+ start(start_),
+ length(len) {}
+ void Print();
+};
+
+struct ErrorMmapShadowOverlap : ErrorBase {
+ const BufferedStackTrace *stack;
+ uptr start, end;
+ ErrorMmapShadowOverlap() = default;
+ ErrorMmapShadowOverlap(u32 tid, BufferedStackTrace *stack_, uptr start_, uptr end_)
+ : ErrorBase(tid, 10, "bad-mmap-overlap"),
+ stack(stack_),
+ start(start_),
+ end(end_) {}
+ void Print();
+};
+
+struct ErrorMmapOutsideRange : ErrorBase {
+ const BufferedStackTrace *stack;
+ uptr start, end;
+ ErrorMmapOutsideRange() = default;
+ ErrorMmapOutsideRange(u32 tid, BufferedStackTrace *stack_, uptr start_, uptr end_)
+ : ErrorBase(tid, 10, "bad-mmap-out-of-range"),
+ stack(stack_),
+ start(start_),
+ end(end_) {}
+ void Print();
+};
+
+struct ErrorMunmapShadowOverlap : ErrorBase {
+ const BufferedStackTrace *stack;
+ uptr start, end;
+ ErrorMunmapShadowOverlap() = default;
+ ErrorMunmapShadowOverlap(u32 tid, BufferedStackTrace *stack_, uptr start_, uptr end_)
+ : ErrorBase(tid, 10, "bad-munmap-overlap"),
+ stack(stack_),
+ start(start_),
+ end(end_) {}
+ void Print();
+};
+
+struct ErrorMunmapOutsideRange : ErrorBase {
+ const BufferedStackTrace *stack;
+ uptr start, end;
+ ErrorMunmapOutsideRange() = default;
+ ErrorMunmapOutsideRange(u32 tid, BufferedStackTrace *stack_, uptr start_, uptr end_)
+ : ErrorBase(tid, 10, "bad-munmap-out-of-range"),
+ stack(stack_),
+ start(start_),
+ end(end_) {}
+ void Print();
+};
+
struct ErrorRssLimitExceeded : ErrorBase {
const BufferedStackTrace *stack;
@@ -433,6 +494,11 @@ struct ErrorGeneric : ErrorBase {
macro(InvalidAlignedAllocAlignment) \
macro(InvalidPosixMemalignAlignment) \
macro(AllocationSizeTooBig) \
+ macro(MmapAddrOverflow) \
+ macro(MmapShadowOverlap) \
+ macro(MmapOutsideRange) \
+ macro(MunmapShadowOverlap) \
+ macro(MunmapOutsideRange) \
macro(RssLimitExceeded) \
macro(OutOfMemory) \
macro(StringFunctionMemoryRangesOverlap) \
diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index 8643271e89d70..5b2b135c41123 100644
--- 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_common.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_libc.h"
@@ -47,6 +48,8 @@
# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
# endif
+#define MAP_FIXED 0x0010 /* [MF|SHM] interpret addr exactly */
+
namespace __asan {
#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
@@ -86,7 +89,25 @@ int OnExit() {
// FIXME: ask frontend whether we need to return failure.
return 0;
}
+static inline bool RangeOverlaps(uptr beg, uptr end_excl, uptr seg_beg, uptr seg_end_incl) {
+ if (!seg_beg && !seg_end_incl) return false;
+ uptr seg_end_excl = seg_end_incl + 1;
+ return beg < seg_end_excl && end_excl > seg_beg;
+}
+
+static inline bool IntersectsShadowOrGap(uptr beg, uptr end_excl) {
+ // Check shadow regions
+ if (RangeOverlaps(beg, end_excl, kLowShadowBeg, kLowShadowEnd)) return true;
+ if (kMidShadowBeg && RangeOverlaps(beg, end_excl, kMidShadowBeg, kMidShadowEnd)) return true;
+ if (RangeOverlaps(beg, end_excl, kHighShadowBeg, kHighShadowEnd)) return true;
+ // Check shadow gaps
+ if (RangeOverlaps(beg, end_excl, kShadowGapBeg, kShadowGapEnd)) return true;
+ if (kShadowGap2Beg && RangeOverlaps(beg, end_excl, kShadowGap2Beg, kShadowGap2End)) return true;
+ if (kShadowGap3Beg && RangeOverlaps(beg, end_excl, kShadowGap3Beg, kShadowGap3End)) return true;
+
+ return false;
+}
} // namespace __asan
// ---------------------- Wrappers ---------------- {{{1
@@ -157,45 +178,98 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
}
template <class Mmap>
-static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
+static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
int prot, int flags, int fd, OFF64_T offset) {
+ if (length == 0)
+ return real_mmap(addr, length, prot, flags, fd, offset);
+
+ uptr start = reinterpret_cast<uptr>(addr);
+ uptr end_excl;
+ if (UNLIKELY(__builtin_add_overflow(start, (uptr)length, &end_excl))) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportMmapAddrOverflow(start, length, &stack);
+ return (void *)-1;
+ }
+
+ if (flags & MAP_FIXED) {
+ if (__asan::IntersectsShadowOrGap(start, end_excl)) {
+ errno = errno_EINVAL;
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportMmapShadowOverlap(start, end_excl, &stack);
+ if (common_flags()->abort_on_error) {
+ Abort();
+ }
+ return (void *)-1;
+ }
+ if (!AddrIsInMem(start) || !AddrIsInMem(end_excl - 1)) {
+ errno = errno_ENOMEM;
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportMmapOutsideRange(start, end_excl, &stack);
+ return (void *)-1;
+ }
+ } else {
+ if (addr && __asan::IntersectsShadowOrGap(start, start + 1))
+ addr = nullptr;
+ }
+
void *res = real_mmap(addr, length, prot, flags, fd, offset);
- if (length && res != (void *)-1) {
+ if (res != (void *)-1) {
const uptr beg = reinterpret_cast<uptr>(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);
+ const uptr page = GetPageSize();
+ const uptr sz = RoundUpTo(length, page);
+ if (AddrIsInMem(beg) && AddrIsInMem(beg + sz - 1)) {
+ PoisonShadow(beg, sz, 0);
+ }
}
return res;
}
template <class Munmap>
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.
+ if (length == 0)
+ return real_munmap(addr, length);
+
const uptr beg = reinterpret_cast<uptr>(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);
+ uptr end_excl;
+ if (UNLIKELY(__builtin_add_overflow(beg, (uptr)length, &end_excl))) {
+ errno = errno_EINVAL;
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportMunmapShadowOverlap(beg, end_excl, &stack);
+ return -1;
+ }
+
+ if ((AddrIsInMem(beg) || AddrIsInMem(end_excl - 1)) &&
+ (!AddrIsInMem(beg) || !AddrIsInMem(end_excl - 1))) {
+ errno = errno_EINVAL;
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportMunmapOutsideRange(beg, end_excl, &stack);
+ return -1;
+ }
+
+ int res = real_munmap(addr, length);
+
+ if (res == 0) {
+ const uptr page = GetPageSize();
+ const uptr aligned_beg = RoundDownTo(beg, page);
+ const uptr aligned_end = RoundUpTo(end_excl, page);
+ if (AddrIsInMem(aligned_beg) && AddrIsInMem(aligned_end - 1)) {
+ PoisonShadow(aligned_beg, aligned_end - aligned_beg, 0);
+ }
}
- return real_munmap(addr, length);
+ return res;
}
-# 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); \
+# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
+ fd, offset) \
+ do { \
+ (void)(ctx); \
+ return mmap_interceptor(REAL(mmap), addr, length, prot, flags, fd, offset); \
} while (false)
# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
do { \
(void)(ctx); \
- return munmap_interceptor(REAL(munmap), addr, sz); \
+ return munmap_interceptor(REAL(munmap), addr, length); \
} while (false)
#if CAN_SANITIZE_LEAKS
diff --git a/compiler-rt/lib/asan/asan_report.cpp b/compiler-rt/lib/asan/asan_report.cpp
index e049a21e4e16d..fbefc63b4dace 100644
--- a/compiler-rt/lib/asan/asan_report.cpp
+++ b/compiler-rt/lib/asan/asan_report.cpp
@@ -343,6 +343,36 @@ void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
in_report.ReportError(error);
}
+void ReportMmapAddrOverflow(uptr start, uptr length, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorMmapAddrOverflow error(GetCurrentTidOrInvalid(), stack, start, length);
+ in_report.ReportError(error);
+}
+
+void ReportMmapShadowOverlap(uptr start, uptr end, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorMmapShadowOverlap error(GetCurrentTidOrInvalid(), stack, start, end);
+ in_report.ReportError(error);
+}
+
+void ReportMmapOutsideRange(uptr start, uptr end, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorMmapOutsideRange error(GetCurrentTidOrInvalid(), stack, start, end);
+ in_report.ReportError(error);
+}
+
+void ReportMunmapShadowOverlap(uptr start, uptr end, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorMunmapShadowOverlap error(GetCurrentTidOrInvalid(), stack, start, end);
+ in_report.ReportError(error);
+}
+
+void ReportMunmapOutsideRange(uptr start, uptr end, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorMunmapOutsideRange error(GetCurrentTidOrInvalid(), stack, start, end);
+ in_report.ReportError(error);
+}
+
void ReportRssLimitExceeded(BufferedStackTrace *stack) {
ScopedInErrorReport in_report(/*fatal*/ true);
ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack);
diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h
index 3143d83abe390..e7f653cf6c3f6 100644
--- a/compiler-rt/lib/asan/asan_report.h
+++ b/compiler-rt/lib/asan/asan_report.h
@@ -73,6 +73,11 @@ void ReportInvalidPosixMemalignAlignment(uptr alignment,
BufferedStackTrace *stack);
void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
BufferedStackTrace *stack);
+void ReportMmapAddrOverflow(uptr start, uptr length, BufferedStackTrace *stack);
+void ReportMmapShadowOverlap(uptr start, uptr end, BufferedStackTrace *stack);
+void ReportMmapOutsideRange(uptr start, uptr end, BufferedStackTrace *stack);
+void ReportMunmapShadowOverlap(uptr start, uptr end, BufferedStackTrace *stack);
+void ReportMunmapOutsideRange(uptr start, uptr end, BufferedStackTrace *stack);
void ReportRssLimitExceeded(BufferedStackTrace *stack);
void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack);
void ReportStringFunctionMemoryRangesOverlap(const char *function,
diff --git a/compiler-rt/test/asan/TestCases/asan_mmap_oob_aix.cpp b/compiler-rt/test/asan/TestCases/asan_mmap_oob_aix.cpp
new file mode 100644
index 0000000000000..e23e18e5e005d
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/asan_mmap_oob_aix.cpp
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// REQUIRES: system-aix
+#include <sys/mman.h>
+
+#define ASAN_AIX_SHADOW_OFFSET 0x0a01000000000000ULL
+
+int main() {
+ size_t map_size = 4096;
+ void* addr = (void*)ASAN_AIX_SHADOW_OFFSET;
+ void* ptr = mmap(addr, map_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if (ptr != MAP_FAILED) munmap(ptr, map_size);
+ return 0;
+}
+
+// CHECK: ERROR: AddressSanitizer: mmap requested memory range
+// CHECK: overlaps with ASan shadow memory
\ No newline at end of file
More information about the llvm-commits
mailing list