mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
Improve stack overflow recovery
It's now possible to use sigaltstack() to recover from stack overflows on Windows. Several bugs in sigaltstack() have been fixed, for all our supported platforms. There's a newer better example showing how to use this, along with three independent unit tests just to further showcase the various techniques.
This commit is contained in:
parent
1694edf85c
commit
4631d34d0d
24 changed files with 590 additions and 274 deletions
|
@ -7,74 +7,104 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigaltstack.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/ucontext.internal.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/ss.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Stack Overflow Demo
|
||||
* stack overflow recovery technique #3
|
||||
* rewrite thread cpu state to call pthread_exit
|
||||
* this method returns gracefully from signal handlers
|
||||
* unfortunately it relies on cpu architecture knowledge
|
||||
*
|
||||
* @see test/libc/thread/stackoverflow1_test.c
|
||||
* @see test/libc/thread/stackoverflow2_test.c
|
||||
* @see test/libc/thread/stackoverflow3_test.c
|
||||
*/
|
||||
|
||||
#define N INT_MAX
|
||||
volatile bool smashed_stack;
|
||||
|
||||
int A(int f(), int n) {
|
||||
if (n < N) {
|
||||
void Exiter(void *rc) {
|
||||
struct sigaltstack ss;
|
||||
ASSERT_SYS(0, 0, sigaltstack(0, &ss));
|
||||
ASSERT_EQ(0, ss.ss_flags);
|
||||
pthread_exit(rc);
|
||||
}
|
||||
|
||||
void CrashHandler(int sig, siginfo_t *si, void *arg) {
|
||||
ucontext_t *ctx = arg;
|
||||
struct sigaltstack ss;
|
||||
ASSERT_SYS(0, 0, sigaltstack(0, &ss));
|
||||
ASSERT_EQ(SS_ONSTACK, ss.ss_flags);
|
||||
kprintf("kprintf avoids overflowing %G %p\n", si->si_signo, si->si_addr);
|
||||
smashed_stack = true;
|
||||
ASSERT_TRUE(__is_stack_overflow(si, ctx));
|
||||
//
|
||||
// the backtrace will look like this
|
||||
//
|
||||
// 0x000000000042561d: pthread_exit at pthread_exit.c:99
|
||||
// 0x0000000000418777: Exiter at stackoverflow2_test.c:40
|
||||
// 0x00000000004186d8: CrashHandler at stackoverflow2_test.c:49
|
||||
// 0x000000000041872a: StackOverflow at stackoverflow2_test.c:53
|
||||
// 0x000000000041872a: StackOverflow at stackoverflow2_test.c:53
|
||||
// 0x000000000041872a: StackOverflow at stackoverflow2_test.c:53
|
||||
// ...
|
||||
//
|
||||
ctx->uc_mcontext.ARG0 = 123;
|
||||
ctx->uc_mcontext.PC = (long)Exiter;
|
||||
ctx->uc_mcontext.SP += 32768;
|
||||
ctx->uc_mcontext.SP &= -16;
|
||||
ctx->uc_mcontext.SP -= 8;
|
||||
}
|
||||
|
||||
int StackOverflow(int f(), int n) {
|
||||
if (n < INT_MAX) {
|
||||
return f(f, n + 1) - 1;
|
||||
} else {
|
||||
return N;
|
||||
return INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
int (*Ap)(int (*)(), int) = A;
|
||||
int (*pStackOverflow)(int (*)(), int) = StackOverflow;
|
||||
|
||||
void *MyPosixThread(void *arg) {
|
||||
struct sigaction sa;
|
||||
struct sigaltstack ss;
|
||||
ss.ss_flags = 0;
|
||||
ss.ss_size = sysconf(_SC_MINSIGSTKSZ) + 4096;
|
||||
ss.ss_sp = gc(malloc(ss.ss_size));
|
||||
ASSERT_SYS(0, 0, sigaltstack(&ss, 0));
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK; // <-- important
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = CrashHandler;
|
||||
sigaction(SIGBUS, &sa, 0);
|
||||
sigaction(SIGSEGV, &sa, 0);
|
||||
exit(pStackOverflow(pStackOverflow, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (IsWindows()) {
|
||||
fprintf(stderr, "stack overflow not possible to catch on windows yet\n");
|
||||
exit(1);
|
||||
}
|
||||
ShowCrashReports();
|
||||
return !!Ap(Ap, 0);
|
||||
void *res;
|
||||
pthread_t th;
|
||||
struct sigaltstack ss;
|
||||
smashed_stack = false;
|
||||
pthread_create(&th, 0, MyPosixThread, 0);
|
||||
pthread_join(th, &res);
|
||||
ASSERT_EQ((void *)123L, res);
|
||||
ASSERT_TRUE(smashed_stack);
|
||||
ASSERT_SYS(0, 0, sigaltstack(0, &ss));
|
||||
ASSERT_EQ(SS_DISABLE, ss.ss_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
error: Uncaught SIGSEGV (Stack Overflow) on rhel5 pid 368
|
||||
./o//examples/stackoverflow.com
|
||||
EUNKNOWN[No error information][0]
|
||||
Linux rhel5 2.6.18-8.el5 #1 SMP Thu Mar 15 19:46:53 EDT 2007
|
||||
|
||||
0x0000000000406896: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||
etc. etc.
|
||||
|
||||
RAX 0000000000000000 RBX 0000000000000001 RDI 000000000040687e ST(0) 0.0
|
||||
RCX 0000000000417125 RDX 000000000041cd70 RSI 0000000000000efe ST(1) 0.0
|
||||
RBP 00006ffffffe1000 RSP 00006ffffffe1000 RIP 0000000000406897 ST(2) 0.0
|
||||
R8 0000000000000000 R9 0000000000000022 R10 0000000000000008 ST(3) 0.0
|
||||
R11 0000000000000293 R12 0000000000000001 R13 00007ffc70b4fc48 ST(4) 0.0
|
||||
R14 00007ffc70b4fc58 R15 00007ffc70b4fd18 VF IF
|
||||
|
||||
XMM0 00000000000000000000000000000000 XMM8 00000000000000000000000000000000
|
||||
XMM1 ffffffffffffeb030000000000000000 XMM9 00000000000000000000000000000000
|
||||
XMM2 0000000000000000ffffffffffffffff XMM10 00000000000000000000000000000000
|
||||
XMM3 00000000000000000000000000000000 XMM11 00000000000000000000000000000000
|
||||
XMM4 00000000000000000000000000000000 XMM12 00000000000000000000000000000000
|
||||
XMM5 00000000000000000000000000000000 XMM13 00000000000000000000000000000000
|
||||
XMM6 00000000000000000000000000000000 XMM14 00000000000000000000000000000000
|
||||
XMM7 00000000000000000000000000000000 XMM15 00000000000000000000000000000000
|
||||
|
||||
100080000000-100080030000 rw-pa-- 3x automap
|
||||
6ffffffe0000-6fffffff0000 rw-paSF 1x stack
|
||||
# 4 frames mapped w/ 0 frames gapped
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue