mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Write test for stack overflow detection
This commit is contained in:
parent
99e67c348b
commit
cef50f2a6b
4 changed files with 96 additions and 7 deletions
|
@ -92,6 +92,7 @@ static void FreeSigAltStack(void *p) {
|
|||
* @see callexitontermination()
|
||||
*/
|
||||
void ShowCrashReports(void) {
|
||||
char *sp;
|
||||
struct sigaltstack ss;
|
||||
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
|
||||
|
@ -105,11 +106,12 @@ void ShowCrashReports(void) {
|
|||
if (!IsWindows()) {
|
||||
bzero(&ss, sizeof(ss));
|
||||
ss.ss_flags = 0;
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
ss.ss_size = GetStackSize();
|
||||
// FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here
|
||||
// OpenBSD sigaltstack() auto-applies MAP_STACK to the memory
|
||||
if ((ss.ss_sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) {
|
||||
if ((sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||
ss.ss_sp = sp;
|
||||
if (!sigaltstack(&ss, &g_oldsigaltstack)) {
|
||||
__cxa_atexit(FreeSigAltStack, ss.ss_sp, 0);
|
||||
} else {
|
||||
|
|
|
@ -47,7 +47,6 @@ _Alignas(64) static int rand64_lock;
|
|||
* @note this function is not intended for cryptography
|
||||
* @note this function passes bigcrush and practrand
|
||||
* @note this function takes at minimum 15 cycles
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -39,6 +40,14 @@
|
|||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
int StackOverflow(int f(), int n) {
|
||||
if (n < INT_MAX) {
|
||||
return f(f, n + 1) - 1;
|
||||
} else {
|
||||
return INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static bool OutputHasSymbol(const char *output, const char *s) {
|
||||
return strstr(output, s) || (!FindDebugBinary() && strstr(output, "NULL"));
|
||||
}
|
||||
|
@ -103,6 +112,7 @@ int (*pRodataOverrunCrash)(int) = RodataOverrunCrash;
|
|||
char *(*pStackOverrunCrash)(int) = StackOverrunCrash;
|
||||
char *(*pMemoryLeakCrash)(void) = MemoryLeakCrash;
|
||||
int (*pNpeCrash)(char *) = NpeCrash;
|
||||
int (*pStackOverflow)(int (*)(), int) = StackOverflow;
|
||||
|
||||
void SetUp(void) {
|
||||
ShowCrashReports();
|
||||
|
@ -130,6 +140,8 @@ void SetUp(void) {
|
|||
case 8:
|
||||
__cxa_finalize(0);
|
||||
exit(pNpeCrash(0));
|
||||
case 9:
|
||||
exit(pStackOverflow(pStackOverflow, 0));
|
||||
default:
|
||||
printf("preventing fork recursion: %s\n", __argv[1]);
|
||||
exit(1);
|
||||
|
@ -428,6 +440,79 @@ TEST(ShowCrashReports, testDivideByZero) {
|
|||
free(output);
|
||||
}
|
||||
|
||||
TEST(ShowCrashReports, testStackOverflow) {
|
||||
if (IsXnu()) return; // TODO(jart): fix me
|
||||
if (IsWindows()) return; // TODO(jart): fix me
|
||||
if (IsFreebsd()) return; // TODO(jart): fix me
|
||||
if (IsOpenbsd()) return; // TODO(jart): fix me
|
||||
size_t got;
|
||||
ssize_t rc;
|
||||
int ws, pid, fds[2];
|
||||
char *output, buf[512];
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "9", "--strace", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
appends(&output, "");
|
||||
for (;;) {
|
||||
rc = read(fds[0], buf, sizeof(buf));
|
||||
if (rc == -1) {
|
||||
ASSERT_EQ(EINTR, errno);
|
||||
continue;
|
||||
}
|
||||
if ((got = rc)) {
|
||||
appendd(&output, buf, got);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fds[0]);
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
EXPECT_TRUE(WIFEXITED(ws));
|
||||
// kprintf("exit status %d\n", WEXITSTATUS(ws));
|
||||
assert(128 + SIGSEGV == WEXITSTATUS(ws) || 77 == WEXITSTATUS(ws));
|
||||
/* NULL is stopgap until we can copy symbol tablces into binary */
|
||||
#ifdef __FNO_OMIT_FRAME_POINTER__
|
||||
if (!OutputHasSymbol(output, "StackOverflow")) {
|
||||
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
|
||||
gc(IndentLines(output, -1, 0, 4)));
|
||||
__die();
|
||||
}
|
||||
#endif
|
||||
// ShowCrashReports() handled it
|
||||
if (!strstr(output, gc(xasprintf("%d", pid)))) {
|
||||
fprintf(stderr, "ERROR: crash report didn't have pid\n%s\n",
|
||||
gc(IndentLines(output, -1, 0, 4)));
|
||||
__die();
|
||||
}
|
||||
if (!strstr(output, "SIGSEGV")) {
|
||||
fprintf(stderr, "ERROR: crash report didn't have signal name\n%s\n",
|
||||
gc(IndentLines(output, -1, 0, 4)));
|
||||
__die();
|
||||
}
|
||||
if (!IsTiny()) {
|
||||
if (!strstr(output, "Stack Overflow")) {
|
||||
fprintf(stderr, "ERROR: crash report didn't have 'Stack Overflow'\n%s\n",
|
||||
gc(IndentLines(output, -1, 0, 4)));
|
||||
__die();
|
||||
}
|
||||
} else {
|
||||
if (!strstr(output, "SEGV_MAPERR")) {
|
||||
fprintf(stderr, "ERROR: crash report didn't have 'SEGV_MAPERR'\n%s\n",
|
||||
gc(IndentLines(output, -1, 0, 4)));
|
||||
__die();
|
||||
}
|
||||
}
|
||||
free(output);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
//
|
||||
// test/libc/log/backtrace_test.c:59: ubsan error: 'int' index 10 into 'char [10]' out of bounds
|
||||
|
|
|
@ -63,8 +63,11 @@ static ssize_t EzWritevAll(int fd, struct iovec *iov, int iovlen) {
|
|||
wrote = 0;
|
||||
}
|
||||
} while (wrote);
|
||||
} else if (errno != EINTR) {
|
||||
return total ? total : -1;
|
||||
} else {
|
||||
WARNF("writev() failed %m");
|
||||
if (errno != EINTR) {
|
||||
return total ? total : -1;
|
||||
}
|
||||
}
|
||||
} while (i < iovlen);
|
||||
return total;
|
||||
|
@ -121,6 +124,7 @@ static int EzTlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) {
|
|||
v[1].iov_base = bio->t;
|
||||
v[1].iov_len = sizeof(bio->t);
|
||||
while ((r = readv(bio->fd, v, 2)) == -1) {
|
||||
WARNF("tls read() error %s", strerror(errno));
|
||||
if (errno == EINTR) {
|
||||
return MBEDTLS_ERR_SSL_WANT_READ;
|
||||
} else if (errno == EAGAIN) {
|
||||
|
@ -128,7 +132,6 @@ static int EzTlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) {
|
|||
} else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) {
|
||||
return MBEDTLS_ERR_NET_CONN_RESET;
|
||||
} else {
|
||||
WARNF("tls read() error %s", strerror(errno));
|
||||
return MBEDTLS_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue