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.
This commit is contained in:
Justine Tunney 2023-11-15 10:48:31 -08:00
parent 3a470ed356
commit e4584ace81
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
6 changed files with 304 additions and 190 deletions

View file

@ -444,6 +444,7 @@ COSMOPOLITAN_H_PKGS = \
THIRD_PARTY_GDTOA \ THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \ THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \ THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_REGEX THIRD_PARTY_REGEX
COSMOCC_PKGS = \ COSMOCC_PKGS = \

View file

@ -19,6 +19,7 @@
#include "libc/atomic.h" #include "libc/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
@ -32,6 +33,7 @@
#include "libc/elf/struct/phdr.h" #include "libc/elf/struct/phdr.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/nt/dll.h" #include "libc/nt/dll.h"
@ -49,6 +51,7 @@
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#include "libc/thread/tls.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.x86_64.freebsd.elf");
__static_yoink(".dlopen.aarch64.glibc.elf"); __static_yoink(".dlopen.aarch64.glibc.elf");
#define PAGE_SIZE 4096
#define XNU_RTLD_LAZY 1 #define XNU_RTLD_LAZY 1
#define XNU_RTLD_NOW 2 #define XNU_RTLD_NOW 2
#define XNU_RTLD_LOCAL 4 #define XNU_RTLD_LOCAL 4
#define XNU_RTLD_GLOBAL 8 #define XNU_RTLD_GLOBAL 8
#define BEGIN_FOREIGN \ struct Loaded {
{ \
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 {
char *base; char *base;
char *entry; char *entry;
Elf64_Ehdr eh; Elf64_Ehdr eh;
@ -100,7 +92,6 @@ static struct {
atomic_uint once; atomic_uint once;
bool is_supported; bool is_supported;
struct CosmoTib *tib; struct CosmoTib *tib;
pthread_mutex_t lock;
void *(*dlopen)(const char *, int); void *(*dlopen)(const char *, int);
void *(*dlsym)(void *, const char *); void *(*dlsym)(void *, const char *);
int (*dlclose)(void *); int (*dlclose)(void *);
@ -108,19 +99,29 @@ static struct {
jmp_buf jb; jmp_buf jb;
} foreign; } 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) { // on system five we sadly need this brutal trampoline
return x & ~align_mask; // 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) { static unsigned get_elf_prot(unsigned x) {
return pgtrunc(x + align_mask);
}
static unsigned pflags(unsigned x) {
unsigned r = 0; unsigned r = 0;
if (x & PF_R) r += PROT_READ; if (x & PF_R) r += PROT_READ;
if (x & PF_W) r += PROT_WRITE; if (x & PF_W) r += PROT_WRITE;
@ -128,32 +129,63 @@ static unsigned pflags(unsigned x) {
return r; 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) { static char *elf_map(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdr) {
uintptr_t minva = -1;
uintptr_t maxva = 0; uintptr_t maxva = 0;
uintptr_t minva = -1;
for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) { for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) {
if (p->p_type != PT_LOAD) continue; if (p->p_type != PT_LOAD) {
if (p->p_vaddr < minva) minva = p->p_vaddr; continue;
if (p->p_vaddr + p->p_memsz > maxva) maxva = p->p_vaddr + p->p_memsz; }
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); __sys_munmap(base, maxva - minva);
for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) { for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) {
if (p->p_type != PT_LOAD) continue; if (p->p_type != PT_LOAD) {
uintptr_t off = p->p_vaddr & align_mask; continue;
uint8_t *start = base; }
start += pgtrunc(p->p_vaddr); uintptr_t skew = p->p_vaddr & (PAGE_SIZE - 1);
size_t sz = pground(p->p_memsz + off); uint8_t *start = base + p->p_vaddr - skew;
uint8_t *m = __sys_mmap(start, sz, PROT_WRITE, 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); MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0);
if (m == MAP_FAILED) return MAP_FAILED; if (m == MAP_FAILED) {
ssize_t rr = pread(fd, m + off, p->p_filesz, p->p_offset); return MAP_FAILED;
if (rr != (ssize_t)p->p_filesz) return MAP_FAILED; }
sys_mprotect(m, sz, pflags(p->p_flags)); 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; return (void *)base;
} }
@ -162,19 +194,29 @@ static int elf_open(const char *file) {
return open(file, O_RDONLY | O_CLOEXEC); return open(file, O_RDONLY | O_CLOEXEC);
} }
static bool elf_slurp(struct loaded *l, int fd, const char *file) { static bool elf_slurp(struct Loaded *l, int fd, const char *file) {
if (pread(fd, &l->eh, 64, 0) != 64) return false; if (pread(fd, &l->eh, 64, 0) != 64) {
if (!IsElf64Binary(&l->eh, 64)) return false; return false;
if (l->eh.e_phnum > ARRAYLEN(l->ph)) 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]); 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; l->entry = (char *)l->eh.e_entry;
return true; return true;
} }
static bool elf_load(struct loaded *l, const char *file) { static bool elf_load(struct Loaded *l, const char *file) {
int fd; int fd;
if ((fd = elf_open(file)) == -1) return false; if ((fd = elf_open(file)) == -1) {
return false;
}
if (!elf_slurp(l, fd, file)) { if (!elf_slurp(l, fd, file)) {
close(fd); close(fd);
return false; 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) { static bool elf_interp(char *buf, size_t bsz, const char *file) {
int fd; int fd;
if ((fd = elf_open(file)) == -1) return false; if ((fd = elf_open(file)) == -1) {
struct loaded l; return false;
}
struct Loaded l;
if (!elf_slurp(&l, fd, file)) { if (!elf_slurp(&l, fd, file)) {
close(fd); close(fd);
return false; 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, static void elf_exec(const char *file, const char *iinterp, int argc,
char **argv, char **envp) { char **argv, char **envp) {
struct Loaded prog;
// get elf information
struct loaded prog;
if (!elf_load(&prog, file)) return; if (!elf_load(&prog, file)) return;
struct loaded interp;
struct Loaded interp;
if (!elf_load(&interp, iinterp)) return; if (!elf_load(&interp, iinterp)) return;
// count environment variables // count environment variables
int envc = 0; int envc = 0;
while (envp[envc]) envc++; while (envp[envc]) envc++;
// create a stack for the new process just beneath our stack // count auxiliary values
long *sp = (long *)__builtin_frame_address(0) - 256; 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 // push auxiliary values
*--sp = 0; *--sp = 0;
Elf64_auxv_t *av;
unsigned long key, val; unsigned long key, val;
for (av = (Elf64_auxv_t *)__auxv; (key = av->a_type); ++av) { for (av = (Elf64_auxv_t *)__auxv; (key = av->a_type); ++av) {
val = av->a_un.a_val; val = av->a_un.a_val;
if (key == AT_PHDR) val = (long)(prog.base + prog.eh.e_phoff); if (key == AT_PHDR) val = (long)(prog.base + prog.eh.e_phoff);
if (key == AT_PHENT) val = prog.eh.e_phentsize; if (key == AT_PHENT) val = prog.eh.e_phentsize;
if (key == AT_PHNUM) val = prog.eh.e_phnum; 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_BASE) val = (long)interp.base;
if (key == AT_FLAGS) val = 0; if (key == AT_FLAGS) val = 0;
if (key == AT_ENTRY) val = (long)prog.entry; 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 = push_strs(sp, argv, argc);
*--sp = argc; *--sp = argc;
STRACE("running dlopen importer %p...", interp.entry);
// XXX: ideally we should set most registers to zero
#ifdef __x86_64__ #ifdef __x86_64__
struct ps_strings { struct ps_strings {
char **argv; char **argv;
@ -285,130 +346,72 @@ static void elf_exec(const char *file, const char *iinterp, int argc,
#endif #endif
} }
static wontreturn void foreign_helper(void **p) { static char *dlerror_set(const char *str) {
foreign.dlopen = p[0]; strlcpy(dlerror_buf, str, sizeof(dlerror_buf));
foreign.dlsym = p[1]; return dlerror_buf;
foreign.dlclose = p[2];
foreign.dlerror = p[3];
longjmp(foreign.jb, 1);
} }
static void foreign_setup(void) { static char *foreign_alloc_block(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";
}
}
#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; char *p = 0;
if ((h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 0, 65536, 0)) && size_t sz = 65536;
(p = MapViewOfFileEx(h, kNtFileMapWrite | kNtFileMapExecute, 0, 0, 65536, if (!IsWindows()) {
0))) { 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);
}
}
if (p) {
WRITE32LE(p, 4); // store used index WRITE32LE(p, 4); // store used index
} else { } else {
last_dlerror = "out of memory"; dlerror_set("out of memory");
} }
return p; return p;
} }
static void *dlsym_nt_alloc_rwx(size_t n) { static void *foreign_alloc(size_t n) {
void *res; void *res;
static char *block; 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 || READ32LE(block) + n > 65536) {
if (!(block = dlsym_nt_alloc_rwx_block())) { if (!(block = foreign_alloc_block())) {
return 0; return 0;
} }
} }
res = block + READ32LE(block); res = block + READ32LE(block);
WRITE32LE(block, READ32LE(block) + n); WRITE32LE(block, READ32LE(block) + n);
pthread_mutex_unlock(&foreign.lock); pthread_mutex_unlock(&lock);
return res; return res;
} }
static void *dlsym_nt_thunk(void *func, void *tramp) { static void *foreign_thunk_sysv(void *func) {
unsigned char *code; 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 // push %rbp
code[0] = 0x55; code[0] = 0x55;
// mov %rsp,%rbp // mov %rsp,%rbp
@ -422,7 +425,7 @@ static void *dlsym_nt_thunk(void *func, void *tramp) {
// movabs $tramp,%r10 // movabs $tramp,%r10
code[14] = 0x49; code[14] = 0x49;
code[15] = 0xba; code[15] = 0xba;
WRITE64LE(code + 16, (uintptr_t)tramp); WRITE64LE(code + 16, (uintptr_t)__sysv2nt14);
// jmp *%r10 // jmp *%r10
code[24] = 0x41; code[24] = 0x41;
code[25] = 0xff; code[25] = 0xff;
@ -430,14 +433,115 @@ static void *dlsym_nt_thunk(void *func, void *tramp) {
return code; 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) { static void *dlsym_nt(void *handle, const char *name) {
long __sysv2nt14();
void *x64_abi_func; void *x64_abi_func;
void *sysv_abi_func = 0; void *sysv_abi_func = 0;
if ((x64_abi_func = GetProcAddress((uintptr_t)handle, name))) { 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 { } else {
last_dlerror = "symbol not found"; dlerror_set("symbol not found: ");
strlcat(dlerror_buf, name, sizeof(dlerror_buf));
} }
return sysv_abi_func; return sysv_abi_func;
} }
@ -516,16 +620,15 @@ void *cosmo_dlopen(const char *path, int mode) {
} else if (IsXnuSilicon()) { } else if (IsXnuSilicon()) {
res = dlopen_silicon(path, mode); res = dlopen_silicon(path, mode);
} else if (IsXnu()) { } 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; res = 0;
} else if (foreign_init()) { } else if (foreign_init()) {
BEGIN_FOREIGN; STRACE("calling platform dlopen %p tib %p...", foreign.dlopen, foreign.tib);
res = foreign.dlopen(path, mode); res = foreign.dlopen(path, mode);
END_FOREIGN;
} else { } else {
res = 0; res = 0;
} }
STRACE("dlopen(%#s, %d) → %p", path, mode, res); STRACE("dlopen(%#s, %d) → %p% m", path, mode, res);
return res; return res;
} }
@ -539,23 +642,23 @@ void *cosmo_dlopen(const char *path, int mode) {
* @return address of symbol, or NULL w/ dlerror() * @return address of symbol, or NULL w/ dlerror()
*/ */
void *cosmo_dlsym(void *handle, const char *name) { void *cosmo_dlsym(void *handle, const char *name) {
void *res; void *func;
if (IsWindows()) { if (IsWindows()) {
res = dlsym_nt(handle, name); func = dlsym_nt(handle, name);
} else if (IsXnuSilicon()) { } else if (IsXnuSilicon()) {
res = __syslib->__dlsym(handle, name); func = __syslib->__dlsym(handle, name);
} else if (IsXnu()) { } 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; func = 0;
} else if (foreign_init()) { } else if (foreign_init()) {
BEGIN_FOREIGN; if ((func = foreign.dlsym(handle, name))) {
res = foreign.dlsym(handle, name); func = foreign_thunk_sysv(func);
END_FOREIGN;
} else {
res = 0;
} }
STRACE("dlsym(%p, %#s) → %p", handle, name, res); } else {
return res; func = 0;
}
STRACE("dlsym(%p, %#s) → %p", handle, name, func);
return func;
} }
/** /**
@ -571,12 +674,10 @@ int cosmo_dlclose(void *handle) {
} else if (IsXnuSilicon()) { } else if (IsXnuSilicon()) {
res = __syslib->__dlclose(handle); res = __syslib->__dlclose(handle);
} else if (IsXnu()) { } 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; res = -1;
} else if (foreign_init()) { } else if (foreign_init()) {
BEGIN_FOREIGN;
res = foreign.dlclose(handle); res = foreign.dlclose(handle);
END_FOREIGN;
} else { } else {
res = -1; res = -1;
} }
@ -592,13 +693,12 @@ char *cosmo_dlerror(void) {
if (IsXnuSilicon()) { if (IsXnuSilicon()) {
res = __syslib->__dlerror(); res = __syslib->__dlerror();
} else if (IsWindows() || IsXnu()) { } else if (IsWindows() || IsXnu()) {
res = (char *)last_dlerror; res = dlerror_buf;
} else if (foreign_init()) { } else if (foreign_init()) {
BEGIN_FOREIGN;
res = foreign.dlerror(); res = foreign.dlerror();
END_FOREIGN; res = dlerror_set(res);
} else { } else {
res = (char *)last_dlerror; res = dlerror_buf;
} }
STRACE("dlerror() → %#s", res); STRACE("dlerror() → %#s", res);
return res; return res;

View file

@ -16,6 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. 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/runtime/stack.h"
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
@ -33,6 +36,11 @@ privileged long __get_safe_size(long want, long extraspace) {
if (!__tls_enabled) return want; if (!__tls_enabled) return want;
struct PosixThread *pt; struct PosixThread *pt;
struct CosmoTib *tib = __get_tls_privileged(); 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(); long bottom, sp = GetStackPointer();
if ((char *)sp >= tib->tib_sigstack_addr && if ((char *)sp >= tib->tib_sigstack_addr &&
(char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) { (char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) {

View file

@ -471,7 +471,6 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
p = b; p = b;
f = fmt; f = fmt;
e = p + n; // assume if n was negative e < p will be the case e = p + n; // assume if n was negative e < p will be the case
tib = __tls_enabled ? __get_tls_privileged() : 0;
for (;;) { for (;;) {
for (;;) { for (;;) {
if (!(c = *f++) || c == '%') break; if (!(c = *f++) || c == '%') break;
@ -582,6 +581,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
goto FormatUnsigned; goto FormatUnsigned;
case 'P': case 'P':
tib = __tls_enabled ? __get_tls_privileged() : 0;
if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) { if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) {
x = __pid; x = __pid;
#ifdef __x86_64__ #ifdef __x86_64__
@ -607,6 +607,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
goto FormatDecimal; goto FormatDecimal;
case 'H': case 'H':
tib = __tls_enabled ? __get_tls_privileged() : 0;
if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) { if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) {
if (tib) { if (tib) {
x = atomic_load_explicit(&tib->tib_tid, memory_order_relaxed); 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': { case 'm': {
int e; int e;
tib = __tls_enabled ? __get_tls_privileged() : 0;
if (!(e = tib ? tib->tib_errno : __errno) && sign == ' ') { if (!(e = tib ? tib->tib_errno : __errno) && sign == ' ') {
break; break;
} else { } else {

View file

@ -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->swd : 0,
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0); ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
*p++ = '\n'; *p++ = '\n';
p = stpcpy(p, "TLS ");
p = HexCpy(p, (long)__get_tls(), 64);
*p++ = '\n';
return p; return p;
} }

View file

@ -176,7 +176,7 @@ struct ElfWriter *elfwriter_open(const char *path, int mode, int arch) {
#elif defined(__riscv) #elif defined(__riscv)
arch = EM_RISCV; arch = EM_RISCV;
#elif defined(__s390x__) #elif defined(__s390x__)
elf->ehdr->e_machine = EM_S390; arch = EM_S390;
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif #endif