Created
August 23, 2022 18:43
-
-
Save Keno/95d5faba39523d1cd57ae57f249394da to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <signal.h> | |
#include <setjmp.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <pthread.h> | |
#include <errno.h> | |
#include <sys/mman.h> | |
static jmp_buf jb; | |
static int exec_num; | |
static const char* astr; | |
static const char* bstr; | |
const char* smsg1; | |
const char* smsg2; | |
void A(void); | |
void B(void); | |
void C(void); | |
void* trigger_error(void*); | |
void stack_spray(void) __attribute__((noinline)) { | |
char stack[] = "This is on the stack in S(). Is it still valid?\n"; | |
smsg1 = stack; | |
} | |
void sighandler(int sig) { | |
char msg1[] = "Handling SIGSEGV signal in signal stack frame S.\n"; | |
char msg2[] = "Checking if the previous stack frames are valid.\n"; | |
smsg1 = msg1; | |
smsg2 = msg2; | |
for (int i = 0; i < 1000; ++i) | |
stack_spray(); | |
write(STDOUT_FILENO, smsg1, strlen(smsg1)); | |
write(STDOUT_FILENO, smsg2, strlen(smsg2)); | |
write(STDOUT_FILENO, astr, strlen(astr)); | |
write(STDOUT_FILENO, bstr, strlen(bstr)); | |
} | |
static uintptr_t thread_stack_begin_addr; | |
static uintptr_t signal_stack_begin_addr; | |
#ifndef PTHREAD_STACK_MIN | |
#define PTHREAD_STACK_MIN 16384 | |
#endif | |
int main(int argc, char** argv) { | |
// Map thread stack | |
void* thread_stack = mmap(NULL, PTHREAD_STACK_MIN, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); | |
if (thread_stack == MAP_FAILED) | |
perror("mmap"), exit(1); | |
thread_stack_begin_addr = (uintptr_t)thread_stack; | |
signal_stack_begin_addr = thread_stack_begin_addr + PTHREAD_STACK_MIN; | |
printf("Mapped thread stack at: %zu\n", thread_stack_begin_addr); | |
// Spin a pthread with that stack | |
pthread_t thread; | |
pthread_attr_t attrs; | |
if ((errno = pthread_attr_init(&attrs)), errno) | |
perror("pthread_attr_init"), exit(1); | |
if ((errno = pthread_attr_setstack(&attrs, thread_stack, PTHREAD_STACK_MIN)), errno) | |
perror("pthread_attr_setstack"), exit(1); | |
pthread_create(&thread, NULL, trigger_error, NULL); | |
// Clean up | |
if ((errno = pthread_attr_destroy(&attrs)), errno) | |
perror("pthread_attr_destroy"), exit(1); | |
void* unused; | |
pthread_join(thread, &unused); | |
} | |
void* trigger_error(void* unused) { | |
(void)unused; | |
// Map signal stack | |
stack_t stk; | |
char* sig_stack = mmap((void*)signal_stack_begin_addr, SIGSTKSZ, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0 ,0); | |
if (sig_stack == MAP_FAILED) | |
perror("mmap"), exit(1); | |
signal_stack_begin_addr = (uintptr_t)sig_stack; | |
if (!(signal_stack_begin_addr < thread_stack_begin_addr)) | |
fprintf(stderr, "Demonstration failed.\n" | |
"Need signal stack to be below the thread stack.\n" | |
"Thread stack: %zu\n" | |
"Signal stack: %zu\n", thread_stack_begin_addr, signal_stack_begin_addr), | |
exit(1); | |
printf("Mapped signal stack at: %zu", signal_stack_begin_addr); | |
if (signal_stack_begin_addr + SIGSTKSZ == thread_stack_begin_addr) | |
printf(" (Exactly before the thread stack)"); | |
putchar('\n'); | |
// Install signal stack | |
stk.ss_sp = sig_stack; | |
stk.ss_size = SIGSTKSZ; | |
stk.ss_flags = 0; | |
if (sigaltstack(&stk, NULL) == -1) | |
perror("sigaltstack"), exit(1); | |
puts("Installed signal stack."); | |
// Install signal handler | |
if (signal(SIGSEGV, sighandler) == SIG_ERR) | |
perror("signal"), exit(1); | |
puts("Installed signal handler."); | |
A(); | |
return NULL; | |
} | |
__attribute__((noinline)) void A(void) { | |
char msg[] = "In stack frame A. Calling B()."; | |
puts(msg); | |
char astrs[] = "This is on the stack in A(). Is it still valid?\n"; | |
astr = astrs; | |
B(); | |
} | |
__attribute__((noinline)) void B(void) { | |
char msg[] = "In stack frame B. Calling setjmp(), then calling C()."; | |
puts(msg); | |
char bstrs[] = "This is on the stack in B(). Is it still valid?\n"; | |
bstr = bstrs; | |
int second_time = setjmp(jb); | |
int first_time = !second_time; | |
if (first_time) { | |
C(); | |
} else { | |
puts("Segfaulting."); | |
raise(SIGSEGV); | |
} | |
} | |
__attribute__((noinline)) void C(void) { | |
char msg[] = "In stack frame C. Now longjmp() back to B()."; | |
puts(msg); | |
longjmp(jb, 1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment