From e4584ace81e57974b9322ec6cf881fab9932e2d9 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 15 Nov 2023 10:48:31 -0800 Subject: [PATCH] Get cosmo_dlopen() working better on System Five Imported functions are now aspected with a trampoline that blocks signals and changes the thread-local storage register. This means bigger more complicated libraries can now be imported even though the whole technique remains fundamentally unsafe. --- Makefile | 1 + libc/dlopen/dlopen.c | 476 ++++++++++++++++++++------------- libc/intrin/getsafesize.greg.c | 8 + libc/intrin/kprintf.greg.c | 4 +- libc/log/oncrash_amd64.c | 3 + tool/build/lib/elfwriter.c | 2 +- 6 files changed, 304 insertions(+), 190 deletions(-) diff --git a/Makefile b/Makefile index 922a3c162..602a08272 100644 --- a/Makefile +++ b/Makefile @@ -444,6 +444,7 @@ COSMOPOLITAN_H_PKGS = \ THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MUSL \ + THIRD_PARTY_ZLIB \ THIRD_PARTY_REGEX COSMOCC_PKGS = \ diff --git a/libc/dlopen/dlopen.c b/libc/dlopen/dlopen.c index bf2da7e12..a3963cc69 100644 --- a/libc/dlopen/dlopen.c +++ b/libc/dlopen/dlopen.c @@ -19,6 +19,7 @@ #include "libc/atomic.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-nt.internal.h" @@ -32,6 +33,7 @@ #include "libc/elf/struct/phdr.h" #include "libc/errno.h" #include "libc/intrin/bits.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/strace.internal.h" #include "libc/limits.h" #include "libc/nt/dll.h" @@ -49,6 +51,7 @@ #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" #include "libc/thread/thread.h" #include "libc/thread/tls.h" @@ -71,25 +74,14 @@ __static_yoink(".dlopen.x86_64.glibc.elf"); __static_yoink(".dlopen.x86_64.freebsd.elf"); __static_yoink(".dlopen.aarch64.glibc.elf"); +#define PAGE_SIZE 4096 + #define XNU_RTLD_LAZY 1 #define XNU_RTLD_NOW 2 #define XNU_RTLD_LOCAL 4 #define XNU_RTLD_GLOBAL 8 -#define BEGIN_FOREIGN \ - { \ - BLOCK_SIGNALS; \ - struct CosmoTib *cosmo_tib = __get_tls(); \ - pthread_mutex_lock(&foreign.lock); \ - __set_tls(foreign.tib) - -#define END_FOREIGN \ - __set_tls(cosmo_tib); \ - pthread_mutex_unlock(&foreign.lock); \ - ALLOW_SIGNALS; \ - } - -struct loaded { +struct Loaded { char *base; char *entry; Elf64_Ehdr eh; @@ -100,7 +92,6 @@ static struct { atomic_uint once; bool is_supported; struct CosmoTib *tib; - pthread_mutex_t lock; void *(*dlopen)(const char *, int); void *(*dlsym)(void *, const char *); int (*dlclose)(void *); @@ -108,19 +99,29 @@ static struct { jmp_buf jb; } foreign; -static _Thread_local const char *last_dlerror; +long __sysv2nt14(); -static const unsigned align_mask = 4095; +static _Thread_local char dlerror_buf[128]; -static uintptr_t pgtrunc(uintptr_t x) { - return x & ~align_mask; +// on system five we sadly need this brutal trampoline +// todo(jart): add tls trampoline to sigaction() handlers +// todo(jart): morph binary to get tls from host c library +static long foreign_tramp(long a, long b, long c, long d, long e, + long func(long, long, long, long, long)) { + long res; + sigset_t mask; + sigset_t block = -1; + struct CosmoTib *tib; + sys_sigprocmask(SIG_SETMASK, &block, &mask); + tib = __get_tls(); + __set_tls(foreign.tib); + res = func(a, b, c, d, e); + __set_tls(tib); + sys_sigprocmask(SIG_SETMASK, &mask, 0); + return res; } -static uintptr_t pground(uintptr_t x) { - return pgtrunc(x + align_mask); -} - -static unsigned pflags(unsigned x) { +static unsigned get_elf_prot(unsigned x) { unsigned r = 0; if (x & PF_R) r += PROT_READ; if (x & PF_W) r += PROT_WRITE; @@ -128,32 +129,63 @@ static unsigned pflags(unsigned x) { return r; } +static int get_host_elf_machine(void) { +#ifdef __x86_64__ + return EM_NEXGEN32E; +#elif defined(__aarch64__) + return EM_AARCH64; +#elif defined(__powerpc64__) + return EM_PPC64; +#elif defined(__riscv) + return EM_RISCV; +#elif defined(__s390x__) + return EM_S390; +#else +#error "unsupported architecture" +#endif +} + static char *elf_map(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdr) { - uintptr_t minva = -1; uintptr_t maxva = 0; + uintptr_t minva = -1; for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) { - if (p->p_type != PT_LOAD) continue; - if (p->p_vaddr < minva) minva = p->p_vaddr; - if (p->p_vaddr + p->p_memsz > maxva) maxva = p->p_vaddr + p->p_memsz; + if (p->p_type != PT_LOAD) { + continue; + } + if (p->p_vaddr < minva) { + minva = p->p_vaddr; + } + if (p->p_vaddr + p->p_memsz > maxva) { + maxva = p->p_vaddr + p->p_memsz; + } + } + minva = minva & -PAGE_SIZE; + uint8_t *base = + __sys_mmap(0, maxva - minva, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, 0); + if (base == MAP_FAILED) { + return MAP_FAILED; } - minva = pgtrunc(minva); - maxva = pground(maxva); - uint8_t *base = __sys_mmap(0, maxva - minva, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0); - if (base == MAP_FAILED) return MAP_FAILED; __sys_munmap(base, maxva - minva); for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) { - if (p->p_type != PT_LOAD) continue; - uintptr_t off = p->p_vaddr & align_mask; - uint8_t *start = base; - start += pgtrunc(p->p_vaddr); - size_t sz = pground(p->p_memsz + off); - uint8_t *m = __sys_mmap(start, sz, PROT_WRITE, + if (p->p_type != PT_LOAD) { + continue; + } + uintptr_t skew = p->p_vaddr & (PAGE_SIZE - 1); + uint8_t *start = base + p->p_vaddr - skew; + size_t mapsize = skew + p->p_memsz; + uint8_t *m = __sys_mmap(start, mapsize, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0); - if (m == MAP_FAILED) return MAP_FAILED; - ssize_t rr = pread(fd, m + off, p->p_filesz, p->p_offset); - if (rr != (ssize_t)p->p_filesz) return MAP_FAILED; - sys_mprotect(m, sz, pflags(p->p_flags)); + if (m == MAP_FAILED) { + return MAP_FAILED; + } + ssize_t rr = pread(fd, m + skew, p->p_filesz, p->p_offset); + if (rr != (ssize_t)p->p_filesz) { + return MAP_FAILED; + } + if (sys_mprotect(m, mapsize, get_elf_prot(p->p_flags))) { + return MAP_FAILED; + } } return (void *)base; } @@ -162,19 +194,29 @@ static int elf_open(const char *file) { return open(file, O_RDONLY | O_CLOEXEC); } -static bool elf_slurp(struct loaded *l, int fd, const char *file) { - if (pread(fd, &l->eh, 64, 0) != 64) return false; - if (!IsElf64Binary(&l->eh, 64)) return false; - if (l->eh.e_phnum > ARRAYLEN(l->ph)) return false; +static bool elf_slurp(struct Loaded *l, int fd, const char *file) { + if (pread(fd, &l->eh, 64, 0) != 64) { + return false; + } + if (!IsElf64Binary(&l->eh, 64) || // + l->eh.e_phnum > sizeof(l->ph) / sizeof(*l->ph) || // + l->eh.e_machine != get_host_elf_machine()) { + enoexec(); + return false; + } int bytes = l->eh.e_phnum * sizeof(l->ph[0]); - if (pread(fd, l->ph, bytes, l->eh.e_phoff) != bytes) return false; + if (pread(fd, l->ph, bytes, l->eh.e_phoff) != bytes) { + return false; + } l->entry = (char *)l->eh.e_entry; return true; } -static bool elf_load(struct loaded *l, const char *file) { +static bool elf_load(struct Loaded *l, const char *file) { int fd; - if ((fd = elf_open(file)) == -1) return false; + if ((fd = elf_open(file)) == -1) { + return false; + } if (!elf_slurp(l, fd, file)) { close(fd); return false; @@ -190,8 +232,10 @@ static bool elf_load(struct loaded *l, const char *file) { static bool elf_interp(char *buf, size_t bsz, const char *file) { int fd; - if ((fd = elf_open(file)) == -1) return false; - struct loaded l; + if ((fd = elf_open(file)) == -1) { + return false; + } + struct Loaded l; if (!elf_slurp(&l, fd, file)) { close(fd); return false; @@ -219,30 +263,44 @@ static long *push_strs(long *sp, char **list, int count) { static void elf_exec(const char *file, const char *iinterp, int argc, char **argv, char **envp) { - - // get elf information - struct loaded prog; + struct Loaded prog; if (!elf_load(&prog, file)) return; - struct loaded interp; + + struct Loaded interp; if (!elf_load(&interp, iinterp)) return; // count environment variables int envc = 0; while (envp[envc]) envc++; - // create a stack for the new process just beneath our stack - long *sp = (long *)__builtin_frame_address(0) - 256; + // count auxiliary values + int auxc = 0; + Elf64_auxv_t *av; + for (av = (Elf64_auxv_t *)__auxv; av->a_type; ++av) auxc++; + + // create environment block for embedded process + // the platform libc will save its location for getenv(), etc. + // we need just enough stack memory beneath it for initialization + char *map; + size_t stksize = 65536; + size_t stkalign = sizeof(char *) * 2; + size_t argsize = (argc + 1 + envc + 1 + auxc * 2 + 1) * sizeof(char *); + size_t mapsize = (stksize + argsize + (PAGE_SIZE - 1)) & -PAGE_SIZE; + size_t skew = (mapsize - argsize) & (stkalign - 1); + map = __sys_mmap(0, mapsize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0); + if (map == MAP_FAILED) return; + long *sp = (long *)(map + mapsize - skew); // push auxiliary values *--sp = 0; - Elf64_auxv_t *av; unsigned long key, val; for (av = (Elf64_auxv_t *)__auxv; (key = av->a_type); ++av) { val = av->a_un.a_val; if (key == AT_PHDR) val = (long)(prog.base + prog.eh.e_phoff); if (key == AT_PHENT) val = prog.eh.e_phentsize; if (key == AT_PHNUM) val = prog.eh.e_phnum; - if (key == AT_PAGESZ) val = 0x1000; + if (key == AT_PAGESZ) val = PAGE_SIZE; if (key == AT_BASE) val = (long)interp.base; if (key == AT_FLAGS) val = 0; if (key == AT_ENTRY) val = (long)prog.entry; @@ -256,6 +314,9 @@ static void elf_exec(const char *file, const char *iinterp, int argc, sp = push_strs(sp, argv, argc); *--sp = argc; + STRACE("running dlopen importer %p...", interp.entry); + + // XXX: ideally we should set most registers to zero #ifdef __x86_64__ struct ps_strings { char **argv; @@ -285,130 +346,72 @@ static void elf_exec(const char *file, const char *iinterp, int argc, #endif } -static wontreturn void foreign_helper(void **p) { - foreign.dlopen = p[0]; - foreign.dlsym = p[1]; - foreign.dlclose = p[2]; - foreign.dlerror = p[3]; - longjmp(foreign.jb, 1); +static char *dlerror_set(const char *str) { + strlcpy(dlerror_buf, str, sizeof(dlerror_buf)); + return dlerror_buf; } -static void foreign_setup(void) { - char interp[256] = {0}; - if (!elf_interp(interp, sizeof(interp), "/usr/bin/env")) return; - const char *dlopen_helper = 0; -#ifdef __x86_64__ - if (IsFreebsd()) { - dlopen_helper = "/zip/.dlopen.x86_64.freebsd.elf"; - } else if (IsLinux()) { - if (fileexists("/lib64/ld-linux-x86-64.so.2")) { - dlopen_helper = "/zip/.dlopen.x86_64.glibc.elf"; - } else { - dlopen_helper = "/zip/.dlopen.x86_64.musl.elf"; +static char *foreign_alloc_block(void) { + char *p = 0; + size_t sz = 65536; + if (!IsWindows()) { + p = __sys_mmap(0, sz, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0); + if (p == MAP_FAILED) { + p = 0; + } + } else { + uintptr_t h; + if ((h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 0, sz, 0))) { + p = MapViewOfFileEx(h, kNtFileMapWrite | kNtFileMapExecute, 0, 0, sz, 0); + CloseHandle(h); } } -#elif defined(__aarch64__) - if (IsLinux()) { - dlopen_helper = "/zip/.dlopen.aarch64.glibc.elf"; - } -#endif - if (!dlopen_helper) { - return; // this platform isn't supported yet - } - struct CosmoTib *cosmo_tib = __get_tls(); - if (!setjmp(foreign.jb)) { - elf_exec(dlopen_helper, interp, 2, - (char *[]){ - program_invocation_name, - (char *)foreign_helper, - NULL, - }, - environ); - return; // if it returns then it failed - } - foreign.tib = __get_tls(); - __set_tls(cosmo_tib); - foreign.is_supported = true; -} - -static bool foreign_init(void) { - bool res; - cosmo_once(&foreign.once, foreign_setup); - if (!(res = foreign.is_supported)) { - last_dlerror = "dlopen() isn't supported on this platform"; - } - return res; -} - -static int dlclose_nt(void *handle) { - int res; - if (FreeLibrary((uintptr_t)handle)) { - res = 0; - } else { - last_dlerror = "FreeLibrary() failed"; - res = -1; - } - return res; -} - -static void *dlopen_nt(const char *path, int mode) { - int n; - uintptr_t handle; - char16_t path16[PATH_MAX + 2]; - if (mode & ~(RTLD_LOCAL | RTLD_LAZY | RTLD_NOW)) { - last_dlerror = "invalid mode"; - return 0; - } - if ((n = __mkntpath(path, path16)) == -1) { - last_dlerror = "path invalid"; - return 0; - } - if (n > 3 && // - path16[n - 3] == '.' && // - path16[n - 2] == 's' && // - path16[n - 1] == 'o') { - path16[n - 2] = 'd'; - path16[n - 1] = 'l'; - path16[n + 0] = 'l'; - path16[n + 1] = 0; - } - if (!(handle = LoadLibrary(path16))) { - last_dlerror = "library not found"; - } - return (void *)handle; -} - -static char *dlsym_nt_alloc_rwx_block(void) { - uintptr_t h; - char *p = 0; - if ((h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 0, 65536, 0)) && - (p = MapViewOfFileEx(h, kNtFileMapWrite | kNtFileMapExecute, 0, 0, 65536, - 0))) { + if (p) { WRITE32LE(p, 4); // store used index } else { - last_dlerror = "out of memory"; + dlerror_set("out of memory"); } return p; } -static void *dlsym_nt_alloc_rwx(size_t n) { +static void *foreign_alloc(size_t n) { void *res; static char *block; - pthread_mutex_lock(&foreign.lock); + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&lock); if (!block || READ32LE(block) + n > 65536) { - if (!(block = dlsym_nt_alloc_rwx_block())) { + if (!(block = foreign_alloc_block())) { return 0; } } res = block + READ32LE(block); WRITE32LE(block, READ32LE(block) + n); - pthread_mutex_unlock(&foreign.lock); + pthread_mutex_unlock(&lock); return res; } -static void *dlsym_nt_thunk(void *func, void *tramp) { +static void *foreign_thunk_sysv(void *func) { unsigned char *code; - if (!(code = dlsym_nt_alloc_rwx(27))) return 0; + if (!(code = foreign_alloc(23))) return 0; + // movabs $func,%r9 + code[0] = 0x49; + code[1] = 0xb9; + WRITE64LE(code + 2, (uintptr_t)func); + // movabs $tramp,%r10 + code[10] = 0x49; + code[11] = 0xba; + WRITE64LE(code + 12, (uintptr_t)foreign_tramp); + // jmp *%r10 + code[20] = 0x41; + code[21] = 0xff; + code[22] = 0xe2; + return code; +} + +static void *foreign_thunk_nt(void *func) { + unsigned char *code; + if (!(code = foreign_alloc(27))) return 0; // push %rbp code[0] = 0x55; // mov %rsp,%rbp @@ -422,7 +425,7 @@ static void *dlsym_nt_thunk(void *func, void *tramp) { // movabs $tramp,%r10 code[14] = 0x49; code[15] = 0xba; - WRITE64LE(code + 16, (uintptr_t)tramp); + WRITE64LE(code + 16, (uintptr_t)__sysv2nt14); // jmp *%r10 code[24] = 0x41; code[25] = 0xff; @@ -430,14 +433,115 @@ static void *dlsym_nt_thunk(void *func, void *tramp) { return code; } +static wontreturn dontinstrument void foreign_helper(void **p) { + foreign.dlopen = foreign_thunk_sysv(p[0]); + foreign.dlsym = foreign_thunk_sysv(p[1]); + foreign.dlclose = foreign_thunk_sysv(p[2]); + foreign.dlerror = foreign_thunk_sysv(p[3]); + longjmp(foreign.jb, 1); +} + +static bool foreign_setup(void) { + char interp[256] = {0}; + if (!elf_interp(interp, sizeof(interp), "/usr/bin/env")) { + return false; + } + const char *dlopen_helper = 0; +#ifdef __x86_64__ + if (IsFreebsd()) { + dlopen_helper = "/zip/.dlopen.x86_64.freebsd.elf"; + } else if (IsLinux()) { + if (fileexists("/lib64/ld-linux-x86-64.so.2")) { + dlopen_helper = "/zip/.dlopen.x86_64.glibc.elf"; + } else { + dlopen_helper = "/zip/.dlopen.x86_64.musl.elf"; + } + } +#elif defined(__aarch64__) + if (0 && IsLinux()) { // TODO(jart): implement me + dlopen_helper = "/zip/.dlopen.aarch64.glibc.elf"; + } +#endif + if (!dlopen_helper) { + enosys(); + return false; // this platform isn't supported yet + } + struct CosmoTib *cosmo_tib = __get_tls(); + if (!setjmp(foreign.jb)) { + elf_exec(dlopen_helper, interp, 2, + (char *[]){ + program_invocation_name, + (char *)foreign_helper, + NULL, + }, + environ); + return false; // if elf_exec() returns, it failed + } + foreign.tib = __get_tls(); + __set_tls(cosmo_tib); + foreign.is_supported = true; + return true; +} + +static void foreign_once(void) { + foreign_setup(); +} + +static bool foreign_init(void) { + bool res; + cosmo_once(&foreign.once, foreign_once); + if (!(res = foreign.is_supported)) { + dlerror_set("dlopen() isn't supported on this platform"); + } + return res; +} + +static int dlclose_nt(void *handle) { + int res; + if (FreeLibrary((uintptr_t)handle)) { + res = 0; + } else { + dlerror_set("FreeLibrary() failed"); + res = -1; + } + return res; +} + +static void *dlopen_nt(const char *path, int mode) { + int n; + uintptr_t handle; + char16_t path16[PATH_MAX + 2]; + if (mode & ~(RTLD_LOCAL | RTLD_LAZY | RTLD_NOW)) { + dlerror_set("invalid mode"); + return 0; + } + if ((n = __mkntpath(path, path16)) == -1) { + dlerror_set("path invalid"); + return 0; + } + if (n > 3 && // + path16[n - 3] == '.' && // + path16[n - 2] == 's' && // + path16[n - 1] == 'o') { + path16[n - 2] = 'd'; + path16[n - 1] = 'l'; + path16[n + 0] = 'l'; + path16[n + 1] = 0; + } + if (!(handle = LoadLibrary(path16))) { + dlerror_set("library not found"); + } + return (void *)handle; +} + static void *dlsym_nt(void *handle, const char *name) { - long __sysv2nt14(); void *x64_abi_func; void *sysv_abi_func = 0; if ((x64_abi_func = GetProcAddress((uintptr_t)handle, name))) { - sysv_abi_func = dlsym_nt_thunk(x64_abi_func, __sysv2nt14); + sysv_abi_func = foreign_thunk_nt(x64_abi_func); } else { - last_dlerror = "symbol not found"; + dlerror_set("symbol not found: "); + strlcat(dlerror_buf, name, sizeof(dlerror_buf)); } return sysv_abi_func; } @@ -516,16 +620,15 @@ void *cosmo_dlopen(const char *path, int mode) { } else if (IsXnuSilicon()) { res = dlopen_silicon(path, mode); } else if (IsXnu()) { - last_dlerror = "dlopen() isn't supported on x86-64 MacOS"; + dlerror_set("dlopen() isn't supported on x86-64 MacOS"); res = 0; } else if (foreign_init()) { - BEGIN_FOREIGN; + STRACE("calling platform dlopen %p tib %p...", foreign.dlopen, foreign.tib); res = foreign.dlopen(path, mode); - END_FOREIGN; } else { res = 0; } - STRACE("dlopen(%#s, %d) → %p", path, mode, res); + STRACE("dlopen(%#s, %d) → %p% m", path, mode, res); return res; } @@ -539,23 +642,23 @@ void *cosmo_dlopen(const char *path, int mode) { * @return address of symbol, or NULL w/ dlerror() */ void *cosmo_dlsym(void *handle, const char *name) { - void *res; + void *func; if (IsWindows()) { - res = dlsym_nt(handle, name); + func = dlsym_nt(handle, name); } else if (IsXnuSilicon()) { - res = __syslib->__dlsym(handle, name); + func = __syslib->__dlsym(handle, name); } else if (IsXnu()) { - last_dlerror = "dlopen() isn't supported on x86-64 MacOS"; - res = 0; + dlerror_set("dlopen() isn't supported on x86-64 MacOS"); + func = 0; } else if (foreign_init()) { - BEGIN_FOREIGN; - res = foreign.dlsym(handle, name); - END_FOREIGN; + if ((func = foreign.dlsym(handle, name))) { + func = foreign_thunk_sysv(func); + } } else { - res = 0; + func = 0; } - STRACE("dlsym(%p, %#s) → %p", handle, name, res); - return res; + STRACE("dlsym(%p, %#s) → %p", handle, name, func); + return func; } /** @@ -571,12 +674,10 @@ int cosmo_dlclose(void *handle) { } else if (IsXnuSilicon()) { res = __syslib->__dlclose(handle); } else if (IsXnu()) { - last_dlerror = "dlopen() isn't supported on x86-64 MacOS"; + dlerror_set("dlopen() isn't supported on x86-64 MacOS"); res = -1; } else if (foreign_init()) { - BEGIN_FOREIGN; res = foreign.dlclose(handle); - END_FOREIGN; } else { res = -1; } @@ -592,13 +693,12 @@ char *cosmo_dlerror(void) { if (IsXnuSilicon()) { res = __syslib->__dlerror(); } else if (IsWindows() || IsXnu()) { - res = (char *)last_dlerror; + res = dlerror_buf; } else if (foreign_init()) { - BEGIN_FOREIGN; res = foreign.dlerror(); - END_FOREIGN; + res = dlerror_set(res); } else { - res = (char *)last_dlerror; + res = dlerror_buf; } STRACE("dlerror() → %#s", res); return res; diff --git a/libc/intrin/getsafesize.greg.c b/libc/intrin/getsafesize.greg.c index 4a1abf0bc..2c0c12251 100644 --- a/libc/intrin/getsafesize.greg.c +++ b/libc/intrin/getsafesize.greg.c @@ -16,6 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/sections.internal.h" +#include "libc/intrin/kprintf.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/stack.h" #include "libc/thread/posixthread.internal.h" #include "libc/thread/tls.h" @@ -33,6 +36,11 @@ privileged long __get_safe_size(long want, long extraspace) { if (!__tls_enabled) return want; struct PosixThread *pt; struct CosmoTib *tib = __get_tls_privileged(); + if (!IsAutoFrame((uintptr_t)tib >> 16) && + !(__executable_start <= (const unsigned char *)tib && + (const unsigned char *)tib < _end)) { + return want; + } long bottom, sp = GetStackPointer(); if ((char *)sp >= tib->tib_sigstack_addr && (char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) { diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 41306f305..592480e1e 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -471,7 +471,6 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, p = b; f = fmt; e = p + n; // assume if n was negative e < p will be the case - tib = __tls_enabled ? __get_tls_privileged() : 0; for (;;) { for (;;) { if (!(c = *f++) || c == '%') break; @@ -582,6 +581,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, goto FormatUnsigned; case 'P': + tib = __tls_enabled ? __get_tls_privileged() : 0; if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) { x = __pid; #ifdef __x86_64__ @@ -607,6 +607,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, goto FormatDecimal; case 'H': + tib = __tls_enabled ? __get_tls_privileged() : 0; if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) { if (tib) { x = atomic_load_explicit(&tib->tib_tid, memory_order_relaxed); @@ -760,6 +761,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, case 'm': { int e; + tib = __tls_enabled ? __get_tls_privileged() : 0; if (!(e = tib ? tib->tib_errno : __errno) && sign == ' ') { break; } else { diff --git a/libc/log/oncrash_amd64.c b/libc/log/oncrash_amd64.c index 2731fa1c9..c93409ebd 100644 --- a/libc/log/oncrash_amd64.c +++ b/libc/log/oncrash_amd64.c @@ -147,6 +147,9 @@ relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) { ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0, ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0); *p++ = '\n'; + p = stpcpy(p, "TLS "); + p = HexCpy(p, (long)__get_tls(), 64); + *p++ = '\n'; return p; } diff --git a/tool/build/lib/elfwriter.c b/tool/build/lib/elfwriter.c index 20b4a7748..e0dc8925d 100644 --- a/tool/build/lib/elfwriter.c +++ b/tool/build/lib/elfwriter.c @@ -176,7 +176,7 @@ struct ElfWriter *elfwriter_open(const char *path, int mode, int arch) { #elif defined(__riscv) arch = EM_RISCV; #elif defined(__s390x__) - elf->ehdr->e_machine = EM_S390; + arch = EM_S390; #else #error "unsupported architecture" #endif