[asan] Reset stack bounds of context

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
This commit is contained in:
Vitaly Buka
2022-07-20 18:23:17 -07:00
parent 6a1ccf61cd
commit c93e4b6b2c
6 changed files with 34 additions and 2 deletions

View File

@@ -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;
@@ -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 *)
@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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()

View File

@@ -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; }

View File

@@ -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>
@@ -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().
@@ -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;