summaryrefslogtreecommitdiff
path: root/compiler-rt
diff options
context:
space:
mode:
authorThurston Dang <thurston@google.com>2023-05-12 23:27:53 +0000
committerThurston Dang <thurston@google.com>2023-05-13 23:03:14 +0000
commitbd1170d2c371283447555bda6057f10e4cb0d25a (patch)
treebeeb8f4e211942b42a7a385eaf613fe9afc5f2b1 /compiler-rt
parent1a83865b786c8dfa27123defcd08e272a30a4c13 (diff)
downloadllvm-bd1170d2c371283447555bda6057f10e4cb0d25a.tar.gz
ASan: fix potential use-after-free in backtrace interceptor
Various ASan interceptors may corrupt memory if passed a pointer to freed memory (https://github.com/google/sanitizers/issues/321). This patch fixes the issue for the backtrace interceptor, by calling REAL(backtrace) with a known-good scratch buffer, and performing an addressability check on the user-provided buffer prior to writing to it. Differential Revision: https://reviews.llvm.org/D150496
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc14
-rw-r--r--compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp6
2 files changed, 11 insertions, 9 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 1c315a5183c6..bc31627ccca5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -4404,12 +4404,16 @@ INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set,
INTERCEPTOR(int, backtrace, void **buffer, int size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size);
- // FIXME: under ASan the call below may write to freed memory and corrupt
- // its metadata. See
- // https://github.com/google/sanitizers/issues/321.
- int res = REAL(backtrace)(buffer, size);
- if (res && buffer)
+ // 'buffer' might be freed memory, hence it is unsafe to directly call
+ // REAL(backtrace)(buffer, size). Instead, we use our own known-good
+ // scratch buffer.
+ void **scratch = (void**)InternalAlloc(sizeof(void*) * size);
+ int res = REAL(backtrace)(scratch, size);
+ if (res && buffer) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
+ internal_memcpy(buffer, scratch, res * sizeof(*buffer));
+ }
+ InternalFree(scratch);
return res;
}
diff --git a/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp b/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp
index bd9da879fe4d..f1ce7d18c0b8 100644
--- a/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp
+++ b/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp
@@ -4,10 +4,6 @@
// restrict the test to glibc.
// REQUIRES: glibc-2.27
-// Interceptor can cause use-after-free
-// (https://github.com/google/sanitizers/issues/321)
-// XFAIL: *
-
// Test the backtrace() interceptor.
#include <assert.h>
@@ -23,6 +19,8 @@ int main() {
assert(buffer != NULL);
free(buffer);
+ // Deliberate use-after-free of 'buffer'. We expect ASan to
+ // catch this, without triggering internal sanitizer errors.
int numEntries = backtrace(buffer, MAX_BT);
printf("backtrace returned %d entries\n", numEntries);