Skip to content

Instantly share code, notes, and snippets.

@Keno
Created August 23, 2022 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Keno/95d5faba39523d1cd57ae57f249394da to your computer and use it in GitHub Desktop.
Save Keno/95d5faba39523d1cd57ae57f249394da to your computer and use it in GitHub Desktop.
#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