Skip to content

Commit

Permalink
[asan] Reset stack bounds of context
Browse files Browse the repository at this point in the history
ClearShadowMemoryForContextStack assumes that context contains the stack
bounds. This is not true for a context from getcontext or oucp of
swapcontext.

Reviewed By: kstoimenov

Differential Revision: https://reviews.llvm.org/D130218
  • Loading branch information
vitalybuka committed Jul 22, 2022
1 parent 6a1ccf6 commit c93e4b6
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 2 deletions.
13 changes: 13 additions & 0 deletions compiler-rt/lib/asan/asan_interceptors.cpp
Expand Up @@ -253,6 +253,14 @@ 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(int, swapcontext, struct ucontext_t *oucp,
struct ucontext_t *ucp) {
static bool reported_warning = false;
Expand All @@ -266,6 +274,10 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
uptr stack, ssize;
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 *)
Expand Down Expand Up @@ -643,6 +655,7 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(longjmp);

#if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(getcontext);
ASAN_INTERCEPT_FUNC(swapcontext);
#endif
#if ASAN_INTERCEPT__LONGJMP
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/asan/asan_internal.h
Expand Up @@ -106,6 +106,7 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle);
void AsanOnDeadlySignal(int, void *siginfo, void *context);

void ReadContextStack(void *context, uptr *stack, uptr *ssize);
void ResetContextStack(void *context);
void StopInitOrderChecking();

// Wrapper for TLS/TSD.
Expand Down
12 changes: 10 additions & 2 deletions compiler-rt/lib/asan/asan_linux.cpp
Expand Up @@ -214,11 +214,19 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
*stack = (uptr)ucp->uc_stack.ss_sp;
*ssize = ucp->uc_stack.ss_size;
}
#else

void ResetContextStack(void *context) {
ucontext_t *ucp = (ucontext_t *)context;
ucp->uc_stack.ss_sp = nullptr;
ucp->uc_stack.ss_size = 0;
}
# else
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
#endif

void ResetContextStack(void *context) { UNIMPLEMENTED(); }
# endif

void *AsanDlSymNext(const char *sym) {
return dlsym(RTLD_NEXT, sym);
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/asan/asan_mac.cpp
Expand Up @@ -99,6 +99,8 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}

void ResetContextStack(void *context) { UNIMPLEMENTED(); }

// Support for the following functions from libdispatch on Mac OS:
// dispatch_async_f()
// dispatch_async()
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/asan/asan_win.cpp
Expand Up @@ -267,6 +267,8 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}

void ResetContextStack(void *context) { UNIMPLEMENTED(); }

void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); }

bool PlatformUnpoisonStacks() { return false; }
Expand Down
6 changes: 6 additions & 0 deletions compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp
Expand Up @@ -9,6 +9,8 @@
// Android and musl do not support swapcontext.
// REQUIRES: x86-target-arch && glibc-2.27

#include <assert.h>
#include <memory.h>
#include <stdio.h>
#include <ucontext.h>
#include <unistd.h>
Expand All @@ -33,6 +35,7 @@ void ThrowAndCatch() {
}

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().
Expand All @@ -50,13 +53,16 @@ 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));
if (swapcontext(&orig_context, &child_context) < 0) {
perror("swapcontext");
return 0;
Expand Down

0 comments on commit c93e4b6

Please sign in to comment.