diff --git a/build/bootstrap/ape.aarch64 b/build/bootstrap/ape.aarch64 index 27fd3d7fb..832fb1ad1 100755 Binary files a/build/bootstrap/ape.aarch64 and b/build/bootstrap/ape.aarch64 differ diff --git a/build/bootstrap/ape.elf b/build/bootstrap/ape.elf index 6a87fd728..5ffffe84b 100755 Binary files a/build/bootstrap/ape.elf and b/build/bootstrap/ape.elf differ diff --git a/build/bootstrap/ape.macho b/build/bootstrap/ape.macho index 42b153c6a..d6d22567b 100755 Binary files a/build/bootstrap/ape.macho and b/build/bootstrap/ape.macho differ diff --git a/build/bootstrap/fixupobj b/build/bootstrap/fixupobj index f63a77fee..ae7d39a9e 100755 Binary files a/build/bootstrap/fixupobj and b/build/bootstrap/fixupobj differ diff --git a/examples/crashreport2.cc b/examples/crashreport2.cc index 06bb92548..d57f3bdea 100644 --- a/examples/crashreport2.cc +++ b/examples/crashreport2.cc @@ -7,6 +7,7 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif +#include "libc/calls/calls.h" #include "libc/math.h" #include "libc/runtime/runtime.h" @@ -18,6 +19,17 @@ void crash(long x0, long x1, long x2, // void (*pCrash)(long, long, long, double, double, double) = crash; int main(int argc, char *argv[]) { + + // // by default we launch an addr2line subprocess to print backtraces + // // with line numbers. you can force it to use the embedded solution + // setenv("ADDR2LINE", "", true); + + // // using a seccomp sandbox is another way to force embedded backtraces + // pledge("stdio", NULL); + + // enable the crash reporting feature ShowCrashReports(); + + // time to die pCrash(1, 2, 3, NAN, NAN, NAN); } diff --git a/libc/calls/pledge.c b/libc/calls/pledge.c index 3ce335cfd..f56af95fa 100644 --- a/libc/calls/pledge.c +++ b/libc/calls/pledge.c @@ -24,11 +24,13 @@ #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/promises.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/intrin/weaken.h" #include "libc/nexgen32e/vendor.internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" +#include "libc/runtime/zipos.internal.h" #include "libc/sysv/consts/pr.h" #include "libc/sysv/errfuns.h" @@ -199,22 +201,22 @@ * `__pledge_mode` is available to improve the experience of pledge() on * Linux. It should specify one of the following penalties: * + * - `PLEDGE_PENALTY_RETURN_EPERM` causes system calls to just return an + * `EPERM` error instead of killing. This is the default on Linux. + * This is a gentler solution that allows code to display a friendly + * warning. Please note this may lead to weird behaviors if the + * software being sandboxed is lazy about checking error results. + * * - `PLEDGE_PENALTY_KILL_THREAD` causes the violating thread to be - * killed. This is the default on Linux. It's effectively the same as - * killing the process, since redbean has no threads. The termination - * signal can't be caught and will be either `SIGSYS` or `SIGABRT`. - * Consider enabling stderr logging below so you'll know why your - * program failed. Otherwise check the system log. + * killed. It's effectively the same as killing the process, since + * redbean has no threads. The termination signal can't be caught and + * will be either `SIGSYS` or `SIGABRT`. Consider enabling stderr + * logging below so you'll know why your program failed. Otherwise + * check the system log. * * - `PLEDGE_PENALTY_KILL_PROCESS` causes the process and all its * threads to be killed. This is always the case on OpenBSD. * - * - `PLEDGE_PENALTY_RETURN_EPERM` causes system calls to just return an - * `EPERM` error instead of killing. This is a gentler solution that - * allows code to display a friendly warning. Please note this may - * lead to weird behaviors if the software being sandboxed is lazy - * about checking error results. - * * `mode` may optionally bitwise or the following flags: * * - `PLEDGE_STDERR_LOGGING` enables friendly error message logging @@ -240,6 +242,8 @@ int pledge(const char *promises, const char *execpromises) { int e, rc; unsigned long ipromises, iexecpromises; + if (_weaken(GetSymbolTable)) + _weaken(GetSymbolTable)(); if (!promises) { // OpenBSD says NULL argument means it doesn't change, i.e. // pledge(0,0) on OpenBSD does nothing. The Cosmopolitan Libc diff --git a/libc/intrin/promises.c b/libc/intrin/promises.c index f549c6db3..a04f9cd8a 100644 --- a/libc/intrin/promises.c +++ b/libc/intrin/promises.c @@ -21,6 +21,6 @@ // XXX: should be inherited thread local // see also sys_pledge_linux() which is 100% pure -int __pledge_mode; +int __pledge_mode = PLEDGE_PENALTY_RETURN_EPERM; unsigned long __promises; unsigned long __execpromises; diff --git a/libc/intrin/x86.h b/libc/intrin/x86.h index 26093109e..8608454f2 100644 --- a/libc/intrin/x86.h +++ b/libc/intrin/x86.h @@ -3,8 +3,8 @@ COSMOPOLITAN_C_START_ enum VendorSignatures { - SIG_INTEL = 0x756e6547, // Genu - SIG_AMD = 0x68747541, // Auth + SIG_INTEL = 0x756e6547, /* Genu */ + SIG_AMD = 0x68747541, /* Auth */ }; enum ProcessorVendors { @@ -139,7 +139,7 @@ struct __processor_model { const char *__cpu_march; }; -struct __processor_model __cpu_model; +extern struct __processor_model __cpu_model; const char *__cpu_march(unsigned); diff --git a/libc/log/addr2linepath.c b/libc/log/addr2linepath.c index 89c09d18b..eb656175e 100644 --- a/libc/log/addr2linepath.c +++ b/libc/log/addr2linepath.c @@ -37,9 +37,14 @@ static struct { } g_addr2line; void GetAddr2linePathInit(void) { + char *res; int e = errno; - const char *path; - if (!(path = getenv("ADDR2LINE"))) { + const char *env, *cmd, *path; + if ((env = getenv("ADDR2LINE"))) { + cmd = env; + path = env; + } else { + cmd = "addr2line"; path = ADDR2LINE; } char *buf = g_addr2line.buf; @@ -48,12 +53,11 @@ void GetAddr2linePathInit(void) { strlcat(buf, "/", PATH_MAX); } strlcat(buf, path, PATH_MAX); - } - if (*buf) { - g_addr2line.res = buf; + res = buf; } else { - g_addr2line.res = commandv("addr2line", buf, PATH_MAX); + res = commandv(cmd, buf, PATH_MAX); } + g_addr2line.res = res; errno = e; } diff --git a/libc/log/backtrace2.c b/libc/log/backtrace2.c index 5c2f7c015..a68d90f05 100644 --- a/libc/log/backtrace2.c +++ b/libc/log/backtrace2.c @@ -66,7 +66,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { } if (!PLEDGED(STDIO) || !PLEDGED(EXEC) || !PLEDGED(EXEC)) { - ShowHint("won't print addr2line backtrace because pledge"); + ShowHint("pledge() sandboxing makes backtraces not as good"); return -1; } diff --git a/libc/log/backtrace3.c b/libc/log/backtrace3.c index 6857d1d6f..b82e12a4a 100644 --- a/libc/log/backtrace3.c +++ b/libc/log/backtrace3.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/cosmo.h" #include "libc/fmt/itoa.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/weaken.h" @@ -29,6 +30,7 @@ #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" #include "libc/str/str.h" +#include "libc/thread/thread.h" #include "libc/thread/tls.h" #define LIMIT 100 @@ -47,8 +49,11 @@ dontinstrument dontasan int PrintBacktraceUsingSymbols( int fd, const struct StackFrame *bp, struct SymbolTable *st) { size_t gi; intptr_t addr; + const char *name; int i, symbol, addend; + static char cxxbuf[8192]; struct Garbages *garbage; + static pthread_spinlock_t lock; const struct StackFrame *frame; (void)gi; if (!bp) @@ -83,8 +88,15 @@ dontinstrument dontasan int PrintBacktraceUsingSymbols( symbol = 0; addend = 0; } - kprintf("%012lx %lx %s%+d\n", frame, addr, __get_symbol_name(st, symbol), - addend); + if ((name = __get_symbol_name(st, symbol)) && __is_mangled(name)) { + pthread_spin_lock(&lock); + __demangle(cxxbuf, name, sizeof(cxxbuf)); + kprintf("%012lx %lx %s%+d\n", frame, addr, cxxbuf, addend); + pthread_spin_unlock(&lock); + name = cxxbuf; + } else { + kprintf("%012lx %lx %s%+d\n", frame, addr, name, addend); + } } return 0; } diff --git a/libc/log/oncrash_arm64.c b/libc/log/oncrash_arm64.c index 47106759f..2ab6d31a1 100644 --- a/libc/log/oncrash_arm64.c +++ b/libc/log/oncrash_arm64.c @@ -31,6 +31,7 @@ #include "libc/calls/struct/utsname.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/ucontext.h" +#include "libc/cosmo.h" #include "libc/cxxabi.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" @@ -40,7 +41,6 @@ #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/macros.internal.h" -#include "libc/mem/mem.h" #include "libc/nexgen32e/stackframe.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" @@ -178,15 +178,15 @@ static relegated bool AppendFileLine(struct Buffer *b, const char *addr2line, } } -static relegated char *GetSymbolName(struct SymbolTable *st, int symbol, - char **mem, size_t *memsz) { - char *s, *t; - if ((s = __get_symbol_name(st, symbol)) && // - s[0] == '_' && s[1] == 'Z' && // - (t = __cxa_demangle(s, *mem, memsz, 0))) { - *mem = s = t; - } - return s; +static relegated char *GetSymbolName(struct SymbolTable *st, int symbol) { + char *str; + static char buf[8192]; + if (!(str = __get_symbol_name(st, symbol))) + return str; + if (!__is_mangled(str)) + return str; + __demangle(buf, str, sizeof(buf)); + return buf; } static relegated void __oncrash_impl(int sig, struct siginfo *si, @@ -241,8 +241,6 @@ static relegated void __oncrash_impl(int sig, struct siginfo *si, : (struct StackFrame *)__builtin_frame_address(0))); if (ctx) { long pc; - char *mem = 0; - size_t memsz = 0; int addend, symbol; const char *debugbin; const char *addr2line; @@ -305,7 +303,7 @@ static relegated void __oncrash_impl(int sig, struct siginfo *si, addend -= st->symbols[symbol].x; Append(b, " "); if (!AppendFileLine(b, addr2line, debugbin, pc)) { - Append(b, "%s", GetSymbolName(st, symbol, &mem, &memsz)); + Append(b, "%s", GetSymbolName(st, symbol)); if (addend) Append(b, "%+d", addend); } @@ -327,7 +325,7 @@ static relegated void __oncrash_impl(int sig, struct siginfo *si, addend -= st->symbols[symbol].x; Append(b, " "); if (!AppendFileLine(b, addr2line, debugbin, pc)) { - Append(b, "%s", GetSymbolName(st, symbol, &mem, &memsz)); + Append(b, "%s", GetSymbolName(st, symbol)); if (addend) Append(b, "%+d", addend); } @@ -367,13 +365,12 @@ static relegated void __oncrash_impl(int sig, struct siginfo *si, } Append(b, " %016lx fp %lx lr ", fp, pc); if (!AppendFileLine(b, addr2line, debugbin, pc) && st) { - Append(b, "%s", GetSymbolName(st, symbol, &mem, &memsz)); + Append(b, "%s", GetSymbolName(st, symbol)); if (addend) Append(b, "%+d", addend); } Append(b, "\n"); } - free(mem); } b->p[b->n - 1] = '\n'; klog(b->p, MIN(b->i, b->n)); diff --git a/libc/mem/tinymalloc.inc b/libc/mem/tinymalloc.inc index f214248aa..fffdcdc6c 100644 --- a/libc/mem/tinymalloc.inc +++ b/libc/mem/tinymalloc.inc @@ -19,10 +19,18 @@ #include "libc/stdckdint.h" #include "libc/str/str.h" +#ifndef TINYMALLOC_MAX_BYTES +#define TINYMALLOC_MAX_BYTES 1073741824 +#endif + +#ifndef TINYMALLOC_MAX_ALIGN +#define TINYMALLOC_MAX_ALIGN 4096 +#endif + #ifndef MODE_DBG /* don't interfere with asan dlmalloc hooking */ -_Alignas(65536) static struct { - char memory[1024 * 1024 * 1024]; +_Alignas(TINYMALLOC_MAX_ALIGN) static struct { + char memory[TINYMALLOC_MAX_BYTES]; unsigned used, last, free; } heap; @@ -59,7 +67,7 @@ void *memalign(size_t align, size_t need) { need = sizeof(unsigned); if (align < sizeof(unsigned)) align = sizeof(unsigned); - if (align > 65536) + if (align > TINYMALLOC_MAX_ALIGN) goto InvalidArgument; if (ckd_add(&need, need, sizeof(unsigned) - 1)) goto OutOfMemory; @@ -86,7 +94,7 @@ void *memalign(size_t align, size_t need) { base &= -align; if (ckd_add(&toto, base, need)) goto OutOfMemory; - if (toto > sizeof(heap.memory)) + if (toto > TINYMALLOC_MAX_BYTES) goto OutOfMemory; res = heap.memory + base; ((unsigned *)res)[-1] = need; @@ -139,7 +147,7 @@ void *realloc(void *ptr, size_t need) { need &= -sizeof(unsigned); if (ckd_add(&toto, base, need)) goto OutOfMemory; - if (toto > sizeof(heap.memory)) + if (toto > TINYMALLOC_MAX_BYTES) goto OutOfMemory; ((unsigned *)mem)[-1] = need; heap.used = toto; diff --git a/libc/runtime/getsymboltable.c b/libc/runtime/getsymboltable.c index b9f8ae2cb..4f87c2762 100644 --- a/libc/runtime/getsymboltable.c +++ b/libc/runtime/getsymboltable.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/errno.h" #include "libc/intrin/promises.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" @@ -124,6 +125,7 @@ struct SymbolTable *GetSymbolTable(void) { struct Zipos *z; if (pthread_spin_trylock(&g_lock)) return 0; + int e = errno; if (!__symtab && !__isworker) { if (_weaken(__zipos_get) && (z = _weaken(__zipos_get)())) { if ((__symtab = GetSymbolTableFromZip(z))) { @@ -137,6 +139,7 @@ struct SymbolTable *GetSymbolTable(void) { __symtab = GetSymbolTableFromElf(); } } + errno = e; pthread_spin_unlock(&g_lock); return __symtab; } diff --git a/libc/str/demangle.c b/libc/str/demangle.c index a290f5485..40d390b32 100644 --- a/libc/str/demangle.c +++ b/libc/str/demangle.c @@ -43,7 +43,7 @@ Copyright (c) 2007 Hyogeol Lee \n\ Copyright (c) 2015-2017 Kai Wang \n\ Copyright (c) 2024 Justine Tunney "); // https://github.com/freebsd/freebsd-src/blob/2176c9ab71c85efd90a6c7af4a9e04fe8e3d49ca/contrib/libcxxrt/libelftc_dem_gnu3.c -// clang -format off +// clang-format off /** * @file demangle.c @@ -321,9 +321,9 @@ static char * vector_str_get_flat(struct cpp_demangle_data *ddata, const struct vector_str *v, size_t *l) { - ssize_t elem_pos, elem_size, rtn_size; size_t i; - char *rtn; + char *rtn, *p; + ssize_t rtn_size; if (!v || !v->size) return 0; @@ -334,14 +334,9 @@ vector_str_get_flat(struct cpp_demangle_data *ddata, const struct vector_str *v, if (!(rtn = (char *)alloc(ddata, 1, rtn_size + 1))) return 0; - elem_pos = 0; - for (i = 0; i < v->size; ++i) { - elem_size = strlen(v->container[i]); - memcpy(rtn + elem_pos, v->container[i], elem_size); - elem_pos += elem_size; - } - - rtn[rtn_size] = '\0'; + p = rtn; + for (i = 0; i < v->size; ++i) + p = stpcpy(p, v->container[i]); if (l) *l = rtn_size; @@ -2878,7 +2873,7 @@ static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata) { struct vector_str *v; - size_t arg_len, idx, limit, size; + size_t arg_len, idx, limit; char *arg; if (!ddata || *ddata->cur == '\0') @@ -2907,12 +2902,7 @@ cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata) if (*ddata->cur == 'E') { ++ddata->cur; - size = v->size; - ASSERT(size > 0); - if (!strncmp(v->container[size - 1], ">", 1)) { - if (!DEM_PUSH_STR(ddata, ">")) - return 0; - } else if (!DEM_PUSH_STR(ddata, ">")) + if (!DEM_PUSH_STR(ddata, ">")) return 0; ddata->is_tmpl = true; break; @@ -4070,6 +4060,7 @@ failure(char *buf, const char *org, size_t buflen) * be a partially copied result. In both cases, -1 is returned. The size * of the output is only returned if this routine is fully succesful. To * successfully cover nearly all the test cases from libcxxabi use 65536 + * and to be able to print 99% of the symbols LLVM's libcxx.a, use 5632. * * It's important to call ismangled() before this, since non-c++ symbols * have a special meaning; for example, "g" will return "__float128". It diff --git a/libc/testlib/testmain.c b/libc/testlib/testmain.c index c87f84ac5..b343aa374 100644 --- a/libc/testlib/testmain.c +++ b/libc/testlib/testmain.c @@ -94,6 +94,12 @@ dontasan int main(int argc, char *argv[]) { struct Dll *e; struct TestAspect *a; + if (errno) { + tinyprint(2, "error: the errno variable was contaminated by constructors\n", + NULL); + return 1; + } + __ubsan_strict = true; __log_level = kLogInfo; GetOpts(argc, argv); diff --git a/test/libc/calls/unveil_test.c b/test/libc/calls/unveil_test.c index 6681eec8d..9e302e878 100644 --- a/test/libc/calls/unveil_test.c +++ b/test/libc/calls/unveil_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/landlock.h" +#include "libc/calls/pledge.h" #include "libc/calls/struct/dirent.h" #include "libc/calls/struct/stat.h" #include "libc/calls/syscall-sysv.internal.h" @@ -337,6 +338,7 @@ TEST(unveil, usedTwice_forbidden_worksWithPledge) { ASSERT_NE(-1, (gotsome = _mapshared(FRAMESIZE))); ASSERT_NE(-1, (pid = fork())); if (!pid) { + __pledge_mode = PLEDGE_PENALTY_KILL_PROCESS; // install our first seccomp filter ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath unveil", 0)); ASSERT_SYS(0, 0, mkdir("jail", 0755));