summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler-rt/lib/asan/asan_interceptors.cpp47
-rw-r--r--compiler-rt/lib/asan/asan_internal.h2
-rw-r--r--compiler-rt/lib/asan/asan_linux.cpp30
-rw-r--r--compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp72
4 files changed, 112 insertions, 39 deletions
diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index 817008253fc0..776f512d08a0 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -257,12 +257,36 @@ static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
PoisonShadow(bottom, ssize, 0);
}
-INTERCEPTOR(int, getcontext, struct ucontext_t *ucp) {
- // API does not requires to have ucp clean, and sets only part of fields. We
- // use ucp->uc_stack to unpoison new stack. We prefer to have zeroes then
- // uninitialized bytes.
- ResetContextStack(ucp);
- return REAL(getcontext)(ucp);
+INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
+ ...) {
+ va_list ap;
+ uptr args[64];
+ // We don't know a better way to forward ... into REAL function. We can
+ // increase args size if neccecary.
+ CHECK_LE(argc, ARRAY_SIZE(args));
+ internal_memset(args, 0, sizeof(args));
+ va_start(ap, argc);
+ for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
+ va_end(ap);
+
+# define ENUMERATE_ARRAY_4(start) \
+ args[start], args[start + 1], args[start + 2], args[start + 3]
+# define ENUMERATE_ARRAY_16(start) \
+ ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
+ ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
+# define ENUMERATE_ARRAY_64() \
+ ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
+ ENUMERATE_ARRAY_16(48)
+
+ REAL(makecontext)
+ ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());
+
+# undef ENUMERATE_ARRAY_4
+# undef ENUMERATE_ARRAY_16
+# undef ENUMERATE_ARRAY_64
+
+ // Sign the stack so we can identify it for unpoisoning.
+ SignContextStack(ucp);
}
INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
@@ -279,9 +303,6 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
ReadContextStack(ucp, &stack, &ssize);
ClearShadowMemoryForContextStack(stack, ssize);
- // See getcontext interceptor.
- ResetContextStack(oucp);
-
# if __has_attribute(__indirect_return__) && \
(defined(__x86_64__) || defined(__i386__))
int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
@@ -658,11 +679,11 @@ void InitializeAsanInterceptors() {
// Intecept jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
-#if ASAN_INTERCEPT_SWAPCONTEXT
- ASAN_INTERCEPT_FUNC(getcontext);
+# if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
-#endif
-#if ASAN_INTERCEPT__LONGJMP
+ ASAN_INTERCEPT_FUNC(makecontext);
+# endif
+# if ASAN_INTERCEPT__LONGJMP
ASAN_INTERCEPT_FUNC(_longjmp);
#endif
#if ASAN_INTERCEPT___LONGJMP_CHK
diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h
index 959fdec26042..a5348e35b297 100644
--- a/compiler-rt/lib/asan/asan_internal.h
+++ b/compiler-rt/lib/asan/asan_internal.h
@@ -105,8 +105,8 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle);
void AsanOnDeadlySignal(int, void *siginfo, void *context);
+void SignContextStack(void *context);
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
-void ResetContextStack(void *context);
void StopInitOrderChecking();
// Wrapper for TLS/TSD.
diff --git a/compiler-rt/lib/asan/asan_linux.cpp b/compiler-rt/lib/asan/asan_linux.cpp
index 3feda5b43dd5..e19b4479aaf3 100644
--- a/compiler-rt/lib/asan/asan_linux.cpp
+++ b/compiler-rt/lib/asan/asan_linux.cpp
@@ -34,6 +34,7 @@
# include "asan_thread.h"
# include "sanitizer_common/sanitizer_flags.h"
# include "sanitizer_common/sanitizer_freebsd.h"
+# include "sanitizer_common/sanitizer_hash.h"
# include "sanitizer_common/sanitizer_libc.h"
# include "sanitizer_common/sanitizer_procmaps.h"
@@ -211,16 +212,29 @@ void AsanCheckIncompatibleRT() {
# endif // SANITIZER_ANDROID
# if ASAN_INTERCEPT_SWAPCONTEXT
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
- ucontext_t *ucp = (ucontext_t *)context;
- *stack = (uptr)ucp->uc_stack.ss_sp;
- *ssize = ucp->uc_stack.ss_size;
+constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;
+
+static int HashContextStack(const ucontext_t &ucp) {
+ MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);
+ hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));
+ hash.add(ucp.uc_stack.ss_size);
+ return static_cast<int>(hash.get());
+}
+
+void SignContextStack(void *context) {
+ ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
+ ucp->uc_stack.ss_flags = HashContextStack(*ucp);
}
-void ResetContextStack(void *context) {
- ucontext_t *ucp = (ucontext_t *)context;
- ucp->uc_stack.ss_sp = nullptr;
- ucp->uc_stack.ss_size = 0;
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);
+ if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) {
+ *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);
+ *ssize = ucp->uc_stack.ss_size;
+ return;
+ }
+ *stack = 0;
+ *ssize = 0;
}
# endif // ASAN_INTERCEPT_SWAPCONTEXT
diff --git a/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp b/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp
index baa18f4a9318..d9381bd7ded6 100644
--- a/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp
+++ b/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp
@@ -20,25 +20,23 @@ ucontext_t child_context;
const int kStackSize = 1 << 20;
-__attribute__((noinline))
-void Throw() {
- throw 1;
-}
+__attribute__((noinline)) void Throw() { throw 1; }
-__attribute__((noinline))
-void ThrowAndCatch() {
+__attribute__((noinline)) void ThrowAndCatch() {
try {
Throw();
- } catch(int a) {
+ } catch (int a) {
printf("ThrowAndCatch: %d\n", a);
}
}
-void Child(int mode) {
- assert(orig_context.uc_stack.ss_size == 0);
- char x[32] = {0}; // Stack gets poisoned.
- printf("Child: %p\n", x);
- ThrowAndCatch(); // Simulate __asan_handle_no_return().
+void Child(int mode, int a, int b, int c) {
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("Child: %d\n", x);
+ assert(a == 'a');
+ assert(b == 'b');
+ assert(c == 'c');
+ ThrowAndCatch(); // Simulate __asan_handle_no_return().
// (a) Do nothing, just return to parent function.
// (b) Jump into the original function. Stack remains poisoned unless we do
// something.
@@ -53,16 +51,13 @@ void Child(int mode) {
int Run(int arg, int mode, char *child_stack) {
printf("Child stack: %p\n", child_stack);
// Setup child context.
- memset(&child_context, 0xff, sizeof(child_context));
getcontext(&child_context);
- assert(child_context.uc_stack.ss_size == 0);
child_context.uc_stack.ss_sp = child_stack;
child_context.uc_stack.ss_size = kStackSize / 2;
if (mode == 0) {
child_context.uc_link = &orig_context;
}
- makecontext(&child_context, (void (*)())Child, 1, mode);
- memset(&orig_context, 0xff, sizeof(orig_context));
+ makecontext(&child_context, (void (*)())Child, 4, mode, 'a', 'b', 'c');
if (swapcontext(&orig_context, &child_context) < 0) {
perror("swapcontext");
return 0;
@@ -74,6 +69,47 @@ int Run(int arg, int mode, char *child_stack) {
return child_stack[arg];
}
+ucontext_t poll_context;
+ucontext_t poller_context;
+
+void Poll() {
+ swapcontext(&poll_context, &poller_context);
+
+ {
+ char x = 0;
+ printf("POLL: %p\n", &x);
+ }
+
+ swapcontext(&poll_context, &poller_context);
+}
+
+void DoRunPoll(char *poll_stack) {
+ getcontext(&poll_context);
+ poll_context.uc_stack.ss_sp = poll_stack;
+ poll_context.uc_stack.ss_size = kStackSize / 2;
+ makecontext(&poll_context, Poll, 0);
+
+ getcontext(&poller_context);
+
+ swapcontext(&poller_context, &poll_context);
+ swapcontext(&poller_context, &poll_context);
+
+ // Touch poll's stack to make sure it's unpoisoned.
+ for (int i = 0; i < kStackSize; i++) {
+ poll_stack[i] = i;
+ }
+}
+
+void RunPoll() {
+ char *poll_stack = new char[kStackSize];
+
+ for (size_t i = 0; i < 2; ++i) {
+ DoRunPoll(poll_stack);
+ }
+
+ delete[] poll_stack;
+}
+
int main(int argc, char **argv) {
char stack[kStackSize + 1];
int ret = 0;
@@ -82,6 +118,8 @@ int main(int argc, char **argv) {
char *heap = new char[kStackSize + 1];
ret += Run(argc - 1, 0, heap);
ret += Run(argc - 1, 1, heap);
- delete [] heap;
+
+ RunPoll();
+ delete[] heap;
return ret;
}