brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · d02e7dc Raw
201 lines · cpp
1// Test hwasan __sanitizer_start_switch_fiber and2// __sanitizer_finish_switch_fiber interface.3 4// RUN: %clangxx_hwasan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s5// RUN: %clangxx_hwasan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s6// RUN: %clangxx_hwasan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s7// RUN: %clangxx_hwasan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s8// RUN: seq 30 | xargs -i -- grep LOOPCHECK %s > %t.checks9// RUN: %clangxx_hwasan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK10// RUN: %clangxx_hwasan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK11// RUN: %clangxx_hwasan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK12// RUN: %clangxx_hwasan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK13 14//15// Android and musl do not support swapcontext.16// REQUIRES: glibc-2.2717 18#include <pthread.h>19#include <setjmp.h>20#include <signal.h>21#include <stdio.h>22#include <sys/time.h>23#include <ucontext.h>24#include <unistd.h>25 26#include <sanitizer/common_interface_defs.h>27 28ucontext_t orig_context;29ucontext_t child_context;30ucontext_t next_child_context;31 32char *next_child_stack;33 34const int kStackSize = 1 << 20;35 36const void *main_thread_stack;37size_t main_thread_stacksize;38 39const void *from_stack;40size_t from_stacksize;41 42// hwasan does not support longjmp with tagged stack pointer, make sure it is43// not tagged.44char __attribute__((no_sanitize("hwaddress"))) allocated_stack[kStackSize + 1];45char __attribute__((46    no_sanitize("hwaddress"))) allocated_child_stack[kStackSize + 1];47 48__attribute__((noinline, noreturn)) void LongJump(jmp_buf env) {49  longjmp(env, 1);50  _exit(1);51}52 53// Simulate __asan_handle_no_return().54__attribute__((noinline)) void CallNoReturn() {55  jmp_buf env;56  if (setjmp(env) != 0)57    return;58 59  LongJump(env);60  _exit(1);61}62 63void NextChild() {64  CallNoReturn();65  __sanitizer_finish_switch_fiber(nullptr, &from_stack, &from_stacksize);66 67  printf("NextChild from: %p %zu\n", from_stack, from_stacksize);68 69  char x[32] = {0}; // Stack gets poisoned.70  printf("NextChild: %p\n", x);71 72  CallNoReturn();73 74  __sanitizer_start_switch_fiber(nullptr, main_thread_stack,75                                 main_thread_stacksize);76  CallNoReturn();77  if (swapcontext(&next_child_context, &orig_context) < 0) {78    perror("swapcontext");79    _exit(1);80  }81}82 83void Child(int mode) {84  CallNoReturn();85  __sanitizer_finish_switch_fiber(nullptr, &main_thread_stack,86                                  &main_thread_stacksize);87  char x[32] = {0}; // Stack gets poisoned.88  printf("Child: %p\n", x);89  CallNoReturn();90  // (a) Do nothing, just return to parent function.91  // (b) Jump into the original function. Stack remains poisoned unless we do92  //     something.93  // (c) Jump to another function which will then jump back to the main function94  if (mode == 0) {95    __sanitizer_start_switch_fiber(nullptr, main_thread_stack,96                                   main_thread_stacksize);97    CallNoReturn();98  } else if (mode == 1) {99    __sanitizer_start_switch_fiber(nullptr, main_thread_stack,100                                   main_thread_stacksize);101    CallNoReturn();102    if (swapcontext(&child_context, &orig_context) < 0) {103      perror("swapcontext");104      _exit(1);105    }106  } else if (mode == 2) {107    printf("NextChild stack: %p\n", next_child_stack);108 109    getcontext(&next_child_context);110    next_child_context.uc_stack.ss_sp = next_child_stack;111    next_child_context.uc_stack.ss_size = kStackSize / 2;112    makecontext(&next_child_context, (void (*)())NextChild, 0);113    __sanitizer_start_switch_fiber(nullptr, next_child_context.uc_stack.ss_sp,114                                   next_child_context.uc_stack.ss_size);115    CallNoReturn();116    if (swapcontext(&child_context, &next_child_context) < 0) {117      perror("swapcontext");118      _exit(1);119    }120  }121}122 123int Run(int arg, int mode, char *child_stack) {124  printf("Child stack: %p\n", child_stack);125  // Setup child context.126  getcontext(&child_context);127  child_context.uc_stack.ss_sp = child_stack;128  child_context.uc_stack.ss_size = kStackSize / 2;129  if (mode == 0) {130    child_context.uc_link = &orig_context;131  }132  makecontext(&child_context, (void (*)())Child, 1, mode);133  CallNoReturn();134  __sanitizer_start_switch_fiber(nullptr, child_context.uc_stack.ss_sp,135                                 child_context.uc_stack.ss_size);136  CallNoReturn();137  if (swapcontext(&orig_context, &child_context) < 0) {138    perror("swapcontext");139    _exit(1);140  }141  CallNoReturn();142  __sanitizer_finish_switch_fiber(nullptr, &from_stack, &from_stacksize);143  CallNoReturn();144  printf("Main context from: %p %zu\n", from_stack, from_stacksize);145 146  return child_stack[arg];147}148 149void handler(int sig) { CallNoReturn(); }150 151int main(int argc, char **argv) {152  // This testcase is copied from ASan's swapcontext_annotation.cpp testcase153  // and adapted to HWASan:154  // 1. removed huge stack test since hwasan has no huge stack limitations155  // 2. stack allocations are now done with original malloc/free instead of156  //   hwasan interceptor, since HWASan does not support tagged stack pointer157  //   in longjmp (see __hwasan_handle_longjmp)158 159  // set up a signal that will spam and trigger __hwasan_handle_vfork at160  // tricky moments161  struct sigaction act = {};162  act.sa_handler = &handler;163  if (sigaction(SIGPROF, &act, 0)) {164    perror("sigaction");165    _exit(1);166  }167 168  itimerval t;169  t.it_interval.tv_sec = 0;170  t.it_interval.tv_usec = 10;171  t.it_value = t.it_interval;172  if (setitimer(ITIMER_PROF, &t, 0)) {173    perror("setitimer");174    _exit(1);175  }176 177  char *heap = allocated_stack;178  next_child_stack = allocated_child_stack;179  int ret = 0;180  // CHECK-NOT: WARNING: HWASan is ignoring requested __hwasan_handle_vfork181  for (unsigned int i = 0; i < 30; ++i) {182    // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]]183    // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288184    ret += Run(argc - 1, 0, heap);185    // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]]186    // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288187    ret += Run(argc - 1, 1, heap);188    // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]]189    // LOOPCHECK: NextChild stack: [[NEXT_CHILD_STACK:0x[0-9a-f]*]]190    // LOOPCHECK: NextChild from: [[CHILD_STACK]] 524288191    // LOOPCHECK: Main context from: [[NEXT_CHILD_STACK]] 524288192    ret += Run(argc - 1, 2, heap);193    printf("Iteration %d passed\n", i);194  }195 196  // CHECK: Test passed197  printf("Test passed\n");198 199  return ret;200}201