diff --git a/ape/ape-m1.c b/ape/ape-m1.c index bf615566c..39a657efc 100644 --- a/ape/ape-m1.c +++ b/ape/ape-m1.c @@ -31,6 +31,7 @@ #include #include +#define pagesz 16384 #define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24) #define SYSLIB_VERSION 1 @@ -57,14 +58,14 @@ struct Syslib { dispatch_time_t (*dispatch_walltime)(const struct timespec *, int64_t); }; -#define TROUBLESHOOT 0 - #define ELFCLASS32 1 #define ELFDATA2LSB 1 #define EM_AARCH64 183 #define ET_EXEC 2 +#define ET_DYN 3 #define PT_LOAD 1 #define PT_DYNAMIC 2 +#define PT_INTERP 3 #define EI_CLASS 4 #define EI_DATA 5 #define PF_X 1 @@ -96,15 +97,14 @@ struct Syslib { #define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110) #define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118) -#define Min(X, Y) ((Y) > (X) ? (X) : (Y)) -#define Roundup(X, K) (((X) + (K)-1) & -(K)) -#define Rounddown(X, K) ((X) & -(K)) +#define MIN(X, Y) ((Y) > (X) ? (X) : (Y)) +#define MAX(X, Y) ((Y) < (X) ? (X) : (Y)) -#define Read32(S) \ +#define READ32(S) \ ((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \ (unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000) -#define Read64(S) \ +#define READ64(S) \ ((unsigned long)(255 & (S)[7]) << 070 | \ (unsigned long)(255 & (S)[6]) << 060 | \ (unsigned long)(255 & (S)[5]) << 050 | \ @@ -144,12 +144,12 @@ struct ElfPhdr { union ElfEhdrBuf { struct ElfEhdr ehdr; - char buf[0x1000]; + char buf[8192]; }; union ElfPhdrBuf { struct ElfPhdr phdr; - char buf[0x1000]; + char buf[4096]; }; struct PathSearcher { @@ -190,29 +190,19 @@ static int StrCmp(const char *l, const char *r) { return (l[i] & 255) - (r[i] & 255); } -static void *MemSet(void *a, int c, unsigned long n) { - char *d = a; - unsigned long i; - for (i = 0; i < n; ++i) { - d[i] = c; +static void Bzero(void *a, unsigned long n) { + long z; + char *p, *e; + p = (char *)a; + e = p + n; + z = 0; + while (p + sizeof(z) <= e) { + __builtin_memcpy(p, &z, sizeof(z)); + p += sizeof(z); } - return d; -} - -static void *MemMove(void *a, const void *b, unsigned long n) { - char *d = a; - unsigned long i; - const char *s = b; - if (d > s) { - for (i = n; i--;) { - d[i] = s[i]; - } - } else { - for (i = 0; i < n; ++i) { - d[i] = s[i]; - } + while (p < e) { + *p++ = 0; } - return d; } static const char *MemChr(const char *s, unsigned char c, unsigned long n) { @@ -224,6 +214,36 @@ static const char *MemChr(const char *s, unsigned char c, unsigned long n) { return 0; } +static void *MemMove(void *a, const void *b, unsigned long n) { + long w; + char *d; + const char *s; + unsigned long i; + d = (char *)a; + s = (const char *)b; + if (d > s) { + while (n >= sizeof(w)) { + n -= sizeof(w); + __builtin_memcpy(&w, s + n, sizeof(n)); + __builtin_memcpy(d + n, &w, sizeof(n)); + } + while (n--) { + d[n] = s[n]; + } + } else { + i = 0; + while (i + sizeof(w) <= n) { + __builtin_memcpy(&w, s + i, sizeof(i)); + __builtin_memcpy(d + i, &w, sizeof(i)); + i += sizeof(w); + } + for (; i < n; ++i) { + d[i] = s[i]; + } + } + return d; +} + static char *GetEnv(char **p, const char *s) { unsigned long i, j; if (p) { @@ -272,19 +292,29 @@ static void Emit(const char *s) { write(2, s, StrLen(s)); } -static void Perror(const char *c, int failed, const char *s) { - char ibuf[21]; - Emit("ape error: "); - Emit(c); - Emit(": "); - Emit(s); - if (failed) { -#include - Emit(" failed errno="); - Itoa(ibuf, errno); - Emit(ibuf); +static long Print(int fd, const char *s, ...) { + int c; + unsigned n; + char b[512]; + __builtin_va_list va; + __builtin_va_start(va, s); + for (n = 0; s; s = __builtin_va_arg(va, const char *)) { + while ((c = *s++)) { + if (n < sizeof(b)) { + b[n++] = c; + } + } } - Emit("\n"); + __builtin_va_end(va); + return write(fd, b, n); +} + +static void Perror(const char *thing, long rc, const char *reason) { + char ibuf[21]; + ibuf[0] = 0; + if (rc) Itoa(ibuf, -rc); + Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "", + ibuf, "\n", 0l); } __attribute__((__noreturn__)) static void Pexit(const char *c, int failed, @@ -416,72 +446,138 @@ static void pthread_jit_write_protect_np_workaround(int enabled) { pthread_jit_write_protect_np(enabled); return; } - Pexit("ape-m1", 0, "failed to set jit write protection"); + Pexit("ape", 0, "failed to set jit write protection"); } __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, long *sp, struct ElfEhdr *e, struct ElfPhdr *p, struct Syslib *lib) { - int prot, flags; - long code, codesize; - unsigned long a, b, i; + long rc; + int prot; + int flags; + int found_entry; + unsigned long dynbase; + unsigned long virtmin, virtmax; + unsigned long a, b, c, d, i, j; - code = 0; - codesize = 0; - for (i = e->e_phnum; i--;) { - if (p[i].p_type == PT_DYNAMIC) { - Pexit(exe, 0, "not a static executable"); - } + /* validate elf */ + found_entry = 0; + virtmin = virtmax = 0; + for (i = 0; i < e->e_phnum; ++i) { if (p[i].p_type != PT_LOAD) { continue; } - if (!p[i].p_memsz) { - continue; - } - if (p[i].p_vaddr & 0x3fff) { - Pexit(exe, 0, "APE phdr addr must be 16384-aligned"); - } - if (p[i].p_offset & 0x3fff) { - Pexit(exe, 0, "APE phdr offset must be 16384-aligned"); + if (p[i].p_filesz > p[i].p_memsz) { + Pexit(exe, 0, "ELF p_filesz exceeds p_memsz"); } if ((p[i].p_flags & (PF_W | PF_X)) == (PF_W | PF_X)) { Pexit(exe, 0, "Apple Silicon doesn't allow RWX memory"); } - prot = 0; - flags = MAP_FIXED | MAP_PRIVATE; - if (p[i].p_flags & PF_R) { - prot |= PROT_READ; + if ((p[i].p_vaddr & (pagesz - 1)) != (p[i].p_offset & (pagesz - 1))) { + Pexit(exe, 0, "ELF p_vaddr incongruent w/ p_offset modulo 16384"); } - if (p[i].p_flags & PF_W) { - prot |= PROT_WRITE; + if (p[i].p_vaddr + p[i].p_memsz < p[i].p_vaddr || + p[i].p_vaddr + p[i].p_memsz + (pagesz - 1) < p[i].p_vaddr) { + Pexit(exe, 0, "ELF p_vaddr + p_memsz overflow"); + } + if (p[i].p_offset + p[i].p_filesz < p[i].p_offset || + p[i].p_offset + p[i].p_filesz + (pagesz - 1) < p[i].p_offset) { + Pexit(exe, 0, "ELF p_offset + p_filesz overflow"); + } + a = p[i].p_vaddr & -pagesz; + b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz; + for (j = i + 1; j < e->e_phnum; ++j) { + if (p[j].p_type != PT_LOAD) continue; + c = p[j].p_vaddr & -pagesz; + d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz; + if (MAX(a, c) < MIN(b, d)) { + Pexit(exe, 0, "ELF segments overlap each others virtual memory"); + } } if (p[i].p_flags & PF_X) { - prot |= PROT_EXEC; - code = p[i].p_vaddr; - codesize = p[i].p_filesz; - } - if (p[i].p_filesz) { - if (mmap((char *)p[i].p_vaddr, p[i].p_filesz, prot, flags, fd, - p[i].p_offset) == MAP_FAILED) { - Pexit(exe, -1, "image mmap()"); - } - if ((a = Min(-p[i].p_filesz & 0x3fff, p[i].p_memsz - p[i].p_filesz))) { - MemSet((void *)(p[i].p_vaddr + p[i].p_filesz), 0, a); + if (p[i].p_vaddr <= e->e_entry && + e->e_entry < p[i].p_vaddr + p[i].p_memsz) { + found_entry = 1; } } - if ((b = Roundup(p[i].p_memsz, 0x4000)) > - (a = Roundup(p[i].p_filesz, 0x4000))) { - if (mmap((char *)p[i].p_vaddr + a, b - a, prot, flags | MAP_ANONYMOUS, -1, - 0) == MAP_FAILED) { - Pexit(exe, -1, "bss mmap()"); - } + if (p[i].p_vaddr < virtmin) { + virtmin = p[i].p_vaddr; + } + if (p[i].p_vaddr + p[i].p_memsz > virtmax) { + virtmax = p[i].p_vaddr + p[i].p_memsz; } } - if (!code) { - Pexit(exe, 0, "ELF needs PT_LOAD phdr w/ PF_X"); + if (!found_entry) { + Pexit(exe, 0, "ELF entrypoint not found in PT_LOAD with PF_X"); } + /* choose loading address for dynamic elf executables + that maintains relative distances between segments */ + if (e->e_type == ET_DYN) { + rc = (long)mmap(0, virtmax - virtmin, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (rc < 0) Pexit(exe, rc, "pie mmap"); + dynbase = rc; + if (dynbase & (pagesz - 1)) { + Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ"); + } + if (dynbase + virtmin < dynbase) { + Pexit(exe, 0, "ELF dynamic base overflow"); + } + } else { + dynbase = 0; + } + + /* load elf */ + for (i = 0; i < e->e_phnum; ++i) { + if (p[i].p_type != PT_LOAD) continue; + if (!p[i].p_memsz) continue; + + /* configure mapping */ + prot = 0; + flags = MAP_FIXED | MAP_PRIVATE; + if (p[i].p_flags & PF_R) prot |= PROT_READ; + if (p[i].p_flags & PF_W) prot |= PROT_WRITE; + if (p[i].p_flags & PF_X) prot |= PROT_EXEC; + + /* load from file */ + if (p[i].p_filesz) { + void *addr; + int prot1, prot2; + unsigned long size; + prot1 = prot; + prot2 = prot; + a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */ + b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */ + c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */ + if (b > c) b = c; + if (c > b && (~prot1 & PROT_WRITE)) { + prot1 = PROT_READ | PROT_WRITE; + } + addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz)); + size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz; + rc = (long)mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz); + if (rc < 0) Pexit(exe, rc, "prog mmap"); + if (c > b) Bzero((void *)(dynbase + a), b - a); + if (prot2 != prot1) { + rc = mprotect(addr, size, prot2); + if (rc < 0) Pexit(exe, rc, "prog mprotect"); + } + } + + /* allocate extra bss */ + a = p[i].p_vaddr + p[i].p_filesz; + a = (a + (pagesz - 1)) & -pagesz; + b = p[i].p_vaddr + p[i].p_memsz; + if (b > a) { + flags |= MAP_ANONYMOUS; + rc = (long)mmap((void *)(dynbase + a), b - a, prot, flags, -1, 0); + if (rc < 0) Pexit(exe, rc, "bss mmap"); + } + } + + /* finish up */ close(fd); register long *x0 asm("x0") = sp; @@ -523,39 +619,116 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, __builtin_unreachable(); } -static void TryElf(struct ApeLoader *M, const char *exe, int fd, long *sp, - long *bp, char *execfn) { +static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, + long *sp, long *bp, char *execfn) { + long i, rc; unsigned size; - if (Read32(M->ehdr.buf) == Read32("\177ELF") && // - M->ehdr.ehdr.e_type == ET_EXEC && // - M->ehdr.ehdr.e_machine == EM_AARCH64 && // - M->ehdr.ehdr.e_ident[EI_CLASS] != ELFCLASS32 && // - M->ehdr.ehdr.e_phentsize >= sizeof(M->phdr.phdr) && // - (size = (unsigned)M->ehdr.ehdr.e_phnum * M->ehdr.ehdr.e_phentsize) <= - sizeof(M->phdr.buf) && - pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff) == size) { - long auxv[][2] = { - {AT_PHDR, (long)&M->phdr.phdr}, // - {AT_PHENT, M->ehdr.ehdr.e_phentsize}, // - {AT_PHNUM, M->ehdr.ehdr.e_phnum}, // - {AT_ENTRY, M->ehdr.ehdr.e_entry}, // - {AT_PAGESZ, 0x4000}, // - {AT_UID, getuid()}, // - {AT_EUID, geteuid()}, // - {AT_GID, getgid()}, // - {AT_EGID, getegid()}, // - {AT_HWCAP, 0xffb3ffffu}, // - {AT_HWCAP2, 0x181}, // - {AT_SECURE, issetugid()}, // - {AT_RANDOM, (long)M->rando}, // - {AT_EXECFN, (long)execfn}, // - {0, 0}, // - }; - _Static_assert(sizeof(auxv) == AUXV_BYTES, - "Please update the AUXV_BYTES constant"); - MemMove(bp, auxv, sizeof(auxv)); - Spawn(exe, fd, sp, &M->ehdr.ehdr, &M->phdr.phdr, &M->lib); + struct ElfEhdr *e; + struct ElfPhdr *p; + + /* validate elf header */ + e = &M->ehdr.ehdr; + if (READ32(M->ehdr.buf) != READ32("\177ELF")) { + return "didn't embed ELF magic"; } + if (e->e_ident[EI_CLASS] == ELFCLASS32) { + return "32-bit ELF isn't supported"; + } + if (e->e_type != ET_EXEC && e->e_type != ET_DYN) { + return "ELF not ET_EXEC or ET_DYN"; + } + if (e->e_machine != EM_AARCH64) { + return "couldn't find ELF header with ARM64 machine type"; + } + if (e->e_phentsize != sizeof(struct ElfPhdr)) { + Pexit(exe, 0, "e_phentsize is wrong"); + } + size = e->e_phnum; + if ((size *= sizeof(struct ElfPhdr)) > sizeof(M->phdr.buf)) { + Pexit(exe, 0, "too many ELF program headers"); + } + + /* read program headers */ + rc = pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff); + if (rc < 0) return "failed to read ELF program headers"; + if (rc != size) return "truncated read of ELF program headers"; + + /* bail on recoverable program header errors */ + p = &M->phdr.phdr; + for (i = 0; i < e->e_phnum; ++i) { + if (p[i].p_type == PT_INTERP) { + return "ELF has PT_INTERP which isn't supported"; + } + if (p[i].p_type == PT_DYNAMIC) { + return "ELF has PT_DYNAMIC which isn't supported"; + } + } + + /* remove empty program headers */ + for (i = 0; i < e->e_phnum;) { + if (p[i].p_type == PT_LOAD && !p[i].p_memsz) { + if (i + 1 < e->e_phnum) { + MemMove(p + i, p + i + 1, + (e->e_phnum - (i + 1)) * sizeof(struct ElfPhdr)); + } + --e->e_phnum; + } else { + ++i; + } + } + + /* + * merge adjacent loads that are contiguous with equal protection, + * which prevents our program header overlap check from needlessly + * failing later on; it also shaves away a microsecond of latency, + * since every program header requires invoking at least 1 syscall + */ + for (i = 0; i + 1 < e->e_phnum;) { + if (p[i].p_type == PT_LOAD && p[i + 1].p_type == PT_LOAD && + ((p[i].p_flags & (PF_R | PF_W | PF_X)) == + (p[i + 1].p_flags & (PF_R | PF_W | PF_X))) && + ((p[i].p_offset + p[i].p_filesz + (pagesz - 1)) & -pagesz) - + (p[i + 1].p_offset & -pagesz) <= + pagesz && + ((p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz) - + (p[i + 1].p_vaddr & -pagesz) <= + pagesz) { + p[i].p_memsz = (p[i + 1].p_vaddr + p[i + 1].p_memsz) - p[i].p_vaddr; + p[i].p_filesz = (p[i + 1].p_offset + p[i + 1].p_filesz) - p[i].p_offset; + if (i + 2 < e->e_phnum) { + MemMove(p + i + 1, p + i + 2, + (e->e_phnum - (i + 2)) * sizeof(struct ElfPhdr)); + } + --e->e_phnum; + } else { + ++i; + } + } + + /* simulate linux auxiliary values */ + long auxv[][2] = { + {AT_PHDR, (long)&M->phdr.phdr}, // + {AT_PHENT, M->ehdr.ehdr.e_phentsize}, // + {AT_PHNUM, M->ehdr.ehdr.e_phnum}, // + {AT_ENTRY, M->ehdr.ehdr.e_entry}, // + {AT_PAGESZ, pagesz}, // + {AT_UID, getuid()}, // + {AT_EUID, geteuid()}, // + {AT_GID, getgid()}, // + {AT_EGID, getegid()}, // + {AT_HWCAP, 0xffb3ffffu}, // + {AT_HWCAP2, 0x181}, // + {AT_SECURE, issetugid()}, // + {AT_RANDOM, (long)M->rando}, // + {AT_EXECFN, (long)execfn}, // + {0, 0}, // + }; + _Static_assert(sizeof(auxv) == AUXV_BYTES, + "Please update the AUXV_BYTES constant"); + MemMove(bp, auxv, sizeof(auxv)); + + /* we're now ready to load */ + Spawn(exe, fd, sp, e, p, &M->lib); } __attribute__((__noinline__)) static long sysret(long rc) { @@ -590,7 +763,7 @@ int main(int argc, char **argv, char **envp) { int c, i, n, fd, rc; struct ApeLoader *M; unsigned char rando[24]; - char *p, *tp, *exe, *prog, *execfn; + char *p, *pe, *tp, *exe, *prog, *execfn; // generate some hard random data if (getentropy(rando, sizeof(rando))) { @@ -673,9 +846,9 @@ int main(int argc, char **argv, char **envp) { argc = sp[3] = sp[0] - 3; argv = (char **)((sp += 3) + 1); } else if (argc < 2) { - Emit("usage: ape-m1 PROG [ARGV1,ARGV2,...]\n" - " ape-m1 - PROG [ARGV0,ARGV1,...]\n" - "actually portable executable loader (apple arm)\n" + Emit("usage: ape PROG [ARGV1,ARGV2,...]\n" + " ape - PROG [ARGV0,ARGV1,...]\n" + "actually portable executable loader silicon 1.4\n" "copyright 2023 justine alexandra roberts tunney\n" "https://justine.lol/ape.html\n"); _exit(1); @@ -692,9 +865,10 @@ int main(int argc, char **argv, char **envp) { Pexit(exe, -1, "open"); } else if ((rc = read(fd, M->ehdr.buf, sizeof(M->ehdr.buf))) < 0) { Pexit(exe, -1, "read"); - } else if (rc != sizeof(M->ehdr.buf)) { + } else if ((unsigned long)rc < sizeof(M->ehdr.ehdr)) { Pexit(exe, 0, "too small"); } + pe = M->ehdr.buf + rc; // resolve argv[0] to reflect path search if (argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) { @@ -713,30 +887,22 @@ int main(int argc, char **argv, char **envp) { // relocate the guest's random numbers MemMove(M->rando, rando, sizeof(M->rando)); - MemSet(rando, 0, sizeof(rando)); - -#if TROUBLESHOOT - for (i = 0; i < argc; ++i) { - Emit("argv = "); - Emit(argv[i]); - Emit("\n"); - } -#endif + Bzero(rando, sizeof(rando)); // ape intended behavior // 1. if file is an elf executable, it'll be used as-is // 2. if ape, will scan shell script for elf printf statements // 3. shell script may have multiple lines producing elf headers - // 4. all elf printf lines must exist in the first 4096 bytes of file + // 4. all elf printf lines must exist in the first 8192 bytes of file // 5. elf program headers may appear anywhere in the binary - if (Read64(M->ehdr.buf) == Read64("MZqFpD='") || - Read64(M->ehdr.buf) == Read64("jartsr='")) { - for (p = M->ehdr.buf; p < M->ehdr.buf + sizeof(M->ehdr.buf); ++p) { - if (Read64(p) != Read64("printf '")) { + if (READ64(M->ehdr.buf) == READ64("MZqFpD='") || + READ64(M->ehdr.buf) == READ64("jartsr='") || + READ64(M->ehdr.buf) == READ64("APEDBG='")) { + for (p = M->ehdr.buf; p < pe; ++p) { + if (READ64(p) != READ64("printf '")) { continue; } - for (i = 0, p += 8; - p + 3 < M->ehdr.buf + sizeof(M->ehdr.buf) && (c = *p++) != '\'';) { + for (i = 0, p += 8; p + 3 < pe && (c = *p++) != '\'';) { if (c == '\\') { if ('0' <= *p && *p <= '7') { c = *p++ - '0'; @@ -751,12 +917,14 @@ int main(int argc, char **argv, char **envp) { } } M->ehdr.buf[i++] = c; + if (i >= sizeof(M->ehdr.buf)) { + break; + } } if (i >= sizeof(M->ehdr.ehdr)) { TryElf(M, exe, fd, sp, bp, execfn); } } } - TryElf(M, exe, fd, sp, bp, execfn); - Pexit(exe, 0, "Not an acceptable APE/ELF executable for AARCH64"); + Pexit(exe, 0, TryElf(M, exe, fd, sp, bp, execfn)); } diff --git a/ape/ape.S b/ape/ape.S index 573bceb6c..41ef92d89 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -610,7 +610,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang // extract the loader into a temp folder, and use it to // load the APE without modifying it. .ascii "[ x\"$1\" != x--assimilate ] && {\n" - .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.3\"\n" + .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.4\"\n" .ascii "[ -x \"$t\" ] || {\n" .ascii "mkdir -p \"${t%/*}\" &&\n" .ascii "dd if=\"$o\" of=\"$t.$$\" skip=" @@ -810,6 +810,19 @@ ape_loader_end: .previous #endif /* SupportsSystemv() || SupportsMetal() */ + .section .note.ape.ident,"a",@progbits + .balign 4 +ape.ident: + .long 2f-1f + .long 4f-3f + .long 1 +1: .asciz "APE" +2: .balign 4 +3: .long 104000000 +4: .size ape.ident,.-ape.ident + .type ape.ident,@object + .previous + #if SupportsOpenbsd() .section .note.openbsd.ident,"a",@progbits .balign 4 @@ -1054,8 +1067,8 @@ ape_pe: .ascin "PE",4 .long RVA(ape_pe_entry) // EntryPoint .long 0 // BaseOfCode .quad ape_pe_base // ImageBase - .long 4096 // SectionAlignment - .long 4096 // FileAlignment + .long ape_pe_sectionalignment // SectionAlignment + .long ape_pe_filealignment // FileAlignment .short v_ntversion // MajorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion .short 0 // MajorImageVersion @@ -1064,7 +1077,7 @@ ape_pe: .ascin "PE",4 .short 0 // MinorSubsystemVersion .long 0 // Win32VersionValue .long RVA(_end) // SizeOfImage - .long RVA(_ehead) // SizeOfHeaders + .long ape_pe_sizeofheaders // SizeOfHeaders .long 0 // Checksum .short v_ntsubsystem // Subsystem: 0=Neutral,2=GUI,3=Console .stub v_ntdllchar,short // DllCharacteristics diff --git a/ape/ape.lds b/ape/ape.lds index 0e8e2d91e..34fdfb73b 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -532,6 +532,11 @@ SECTIONS { } } +ape_pe_filealignment = 512; +ape_pe_sectionalignment = 4096; +ape_pe_sizeofheaders = SIZEOF(.head); +ape_pe_sizeofimage = ROUNDUP(_end - __executable_start, ape_pe_sectionalignment); + PFSTUB8(ape_elf_entry, _start); PFSTUB8(ape_elf_phoff, RVA(ape_phdrs)); PFSTUB8(ape_elf_shoff, 0); @@ -720,6 +725,7 @@ CHURN(WinMain); #define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain)) PFSTUB4(ape_pe_offset, ape_pe - ape_mz); ape_pe_optsz = ape_pe_sections - (ape_pe + 24); +ASSERT(ape_pe_optsz % 8 == 0, "SizeOfOptionalHeader must be multiple of 8"); ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40; ape_pe_base = IMAGE_BASE_VIRTUAL; ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0; diff --git a/ape/apeuninstall.sh b/ape/apeuninstall.sh index 49889aac6..69a18d568 100755 --- a/ape/apeuninstall.sh +++ b/ape/apeuninstall.sh @@ -36,6 +36,7 @@ rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape" for x in .ape \ .ape-1.1 \ .ape-1.3 \ + .ape-1.4 \ .ape-blink-0.9.2 \ .ape-blink-1.0.0; do rm -f \ diff --git a/ape/loader.c b/ape/loader.c index 1d8297f4f..a02d675b3 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -510,8 +510,7 @@ static char SearchPath(struct PathSearcher *ps, const char *suffix) { } static char FindCommand(struct PathSearcher *ps, const char *suffix) { - if (MemChr(ps->name, '/', ps->namelen) || - MemChr(ps->name, '\\', ps->namelen)) { + if (MemChr(ps->name, '/', ps->namelen)) { ps->path[0] = 0; return AccessCommand(ps, suffix, 0); } @@ -556,18 +555,9 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, Pexit(os, exe, 0, "AT_PAGESZ isn't two power"); } for (i = 0; i < e->e_phnum; ++i) { - if (p[i].p_type == PT_INTERP) { - Pexit(os, exe, 0, "ELF has PT_INTERP which isn't supported"); - } - if (p[i].p_type == PT_DYNAMIC) { - Pexit(os, exe, 0, "ELF has PT_DYNAMIC which isn't supported"); - } if (p[i].p_type != PT_LOAD) { continue; } - if (!p[i].p_memsz) { - continue; - } if (p[i].p_filesz > p[i].p_memsz) { Pexit(os, exe, 0, "ELF p_filesz exceeds p_memsz"); } @@ -578,9 +568,9 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, p[i].p_vaddr + p[i].p_memsz + (pagesz - 1) < p[i].p_vaddr) { Pexit(os, exe, 0, "ELF p_vaddr + p_memsz overflow"); } - if (p[i].p_vaddr + p[i].p_filesz < p[i].p_vaddr || - p[i].p_vaddr + p[i].p_filesz + (pagesz - 1) < p[i].p_vaddr) { - Pexit(os, exe, 0, "ELF p_vaddr + p_filesz overflow"); + if (p[i].p_offset + p[i].p_filesz < p[i].p_offset || + p[i].p_offset + p[i].p_filesz + (pagesz - 1) < p[i].p_offset) { + Pexit(os, exe, 0, "ELF p_offset + p_filesz overflow"); } a = p[i].p_vaddr & -pagesz; b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz; @@ -637,7 +627,6 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, /* load elf */ for (i = 0; i < e->e_phnum; ++i) { if (p[i].p_type != PT_LOAD) continue; - if (!p[i].p_memsz) continue; /* configure mapping */ prot = 0; @@ -692,53 +681,122 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, long *sp, long *auxv, unsigned long pagesz, int os) { - long rc; + long i, rc; unsigned size; + struct ElfEhdr *e; + struct ElfPhdr *p; + + /* validate page size */ + if (!pagesz) pagesz = 4096; + if (pagesz & (pagesz - 1)) { + Pexit(os, exe, 0, "AT_PAGESZ isn't two power"); + } + + /* validate elf header */ + e = &M->ehdr.ehdr; if (READ32(M->ehdr.buf) != READ32("\177ELF")) { return "didn't embed ELF magic"; } - if (M->ehdr.ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + if (e->e_ident[EI_CLASS] == ELFCLASS32) { return "32-bit ELF isn't supported"; } - if (M->ehdr.ehdr.e_type != ET_EXEC && M->ehdr.ehdr.e_type != ET_DYN) { + if (e->e_type != ET_EXEC && e->e_type != ET_DYN) { return "ELF not ET_EXEC or ET_DYN"; } - if (M->ehdr.ehdr.e_machine != EM_NEXGEN32E) { + if (e->e_machine != EM_NEXGEN32E) { return "couldn't find ELF header with x86-64 machine type"; } - if (M->ehdr.ehdr.e_phentsize < sizeof(M->phdr.phdr)) { - return "e_phentsize is too small"; + if (e->e_phentsize != sizeof(struct ElfPhdr)) { + Pexit(os, exe, 0, "e_phentsize is wrong"); } - size = M->ehdr.ehdr.e_phnum; - if ((size *= M->ehdr.ehdr.e_phentsize) > sizeof(M->phdr.buf)) { - return "too many ELF program headers"; + size = e->e_phnum; + if ((size *= sizeof(struct ElfPhdr)) > sizeof(M->phdr.buf)) { + Pexit(os, exe, 0, "too many ELF program headers"); } - rc = Pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff, os); + + /* read program headers */ + rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os); if (rc < 0) return "failed to read ELF program headers"; if (rc != size) return "truncated read of ELF program headers"; + + /* bail on recoverable program header errors */ + p = &M->phdr.phdr; + for (i = 0; i < e->e_phnum; ++i) { + if (p[i].p_type == PT_INTERP) { + return "ELF has PT_INTERP which isn't supported"; + } + if (p[i].p_type == PT_DYNAMIC) { + return "ELF has PT_DYNAMIC which isn't supported"; + } + } + + /* remove empty program headers */ + for (i = 0; i < e->e_phnum;) { + if (p[i].p_type == PT_LOAD && !p[i].p_memsz) { + if (i + 1 < e->e_phnum) { + MemMove(p + i, p + i + 1, + (e->e_phnum - (i + 1)) * sizeof(struct ElfPhdr)); + } + --e->e_phnum; + } else { + ++i; + } + } + + /* + * merge adjacent loads that are contiguous with equal protection, + * which prevents our program header overlap check from needlessly + * failing later on; it also shaves away a microsecond of latency, + * since every program header requires invoking at least 1 syscall + */ + for (i = 0; i + 1 < e->e_phnum;) { + if (p[i].p_type == PT_LOAD && p[i + 1].p_type == PT_LOAD && + ((p[i].p_flags & (PF_R | PF_W | PF_X)) == + (p[i + 1].p_flags & (PF_R | PF_W | PF_X))) && + ((p[i].p_offset + p[i].p_filesz + (pagesz - 1)) & -pagesz) - + (p[i + 1].p_offset & -pagesz) <= + pagesz && + ((p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz) - + (p[i + 1].p_vaddr & -pagesz) <= + pagesz) { + p[i].p_memsz = (p[i + 1].p_vaddr + p[i + 1].p_memsz) - p[i].p_vaddr; + p[i].p_filesz = (p[i + 1].p_offset + p[i + 1].p_filesz) - p[i].p_offset; + if (i + 2 < e->e_phnum) { + MemMove(p + i + 1, p + i + 2, + (e->e_phnum - (i + 2)) * sizeof(struct ElfPhdr)); + } + --e->e_phnum; + } else { + ++i; + } + } + + /* fixup operating system provided auxiliary values */ for (; *auxv; auxv += 2) { switch (*auxv) { case AT_PHDR: auxv[1] = (unsigned long)&M->phdr; break; case AT_PHENT: - auxv[1] = M->ehdr.ehdr.e_phentsize; + auxv[1] = e->e_phentsize; break; case AT_PHNUM: - auxv[1] = M->ehdr.ehdr.e_phnum; + auxv[1] = e->e_phnum; break; default: break; } } - Spawn(os, exe, fd, sp, pagesz, &M->ehdr.ehdr, &M->phdr.phdr); + + /* we're now ready to load */ + Spawn(os, exe, fd, sp, pagesz, e, p); } static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) { Print(os, fd, "NAME\n" "\n" - " actually portable executable loader v1.3\n" + " actually portable executable loader version 1.4\n" " copyright 2023 justine alexandra roberts tunney\n" " https://justine.lol/ape.html\n" "\n" diff --git a/ape/start.S b/ape/start.S index 0c2e5ee80..32b61543f 100644 --- a/ape/start.S +++ b/ape/start.S @@ -49,3 +49,13 @@ netbsd.ident: 3: .long 901000000 4: .size netbsd.ident,.-netbsd.ident .type netbsd.ident,@object + .balign 4 +ape.ident: + .long 2f-1f + .long 4f-3f + .long 1 +1: .asciz "APE" +2: .balign 4 +3: .long 104000000 +4: .size ape.ident,.-ape.ident + .type ape.ident,@object diff --git a/build/bootstrap/ape.elf b/build/bootstrap/ape.elf index 147a98189..5c1720dcd 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 26eaef6a1..3a8fecf40 100755 Binary files a/build/bootstrap/ape.macho and b/build/bootstrap/ape.macho differ diff --git a/build/bootstrap/ape.silicon b/build/bootstrap/ape.silicon new file mode 100755 index 000000000..d918ddea4 Binary files /dev/null and b/build/bootstrap/ape.silicon differ diff --git a/examples/showdown.c b/examples/showdown.c deleted file mode 100644 index a56f18a50..000000000 --- a/examples/showdown.c +++ /dev/null @@ -1,26 +0,0 @@ -#if 0 -/*─────────────────────────────────────────────────────────────────╗ -│ To the extent possible under law, Justine Tunney has waived │ -│ all copyright and related or neighboring rights to this file, │ -│ as it is written in the following disclaimers: │ -│ • http://unlicense.org/ │ -│ • http://creativecommons.org/publicdomain/zero/1.0/ │ -╚─────────────────────────────────────────────────────────────────*/ -#endif -#include "libc/calls/calls.h" -#include "libc/calls/struct/iovec.h" -#include "libc/errno.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" - -int main(int argc, char *argv[]) { - char buf[65536]; - memset(buf, '\n', sizeof(buf)); - for (;;) { - ssize_t rc = writev(1, &(struct iovec){buf, sizeof(buf)}, 1); - if (rc != sizeof(buf)) { - printf("got %ld (%s)\n", rc, strerror(errno)); - return 1; - } - } -} diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index 186f66d4c..e989f9109 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -85,8 +85,8 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) { (CanExecute((ape = "/usr/bin/ape")) || CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"), firstnonnull(getenv("HOME"), ".")), - ".ape-1.3", buf))) || - CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.3", + ".ape-1.4", buf))) || + CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.4", buf))))) { shargs[0] = ape; shargs[1] = "-"; diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 35920dc58..84ff0e99f 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -48,8 +48,6 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -#undef sigaction - #ifdef SYSDEBUG STATIC_YOINK("strsignal"); // for kprintf() #endif diff --git a/libc/calls/struct/winsize.internal.h b/libc/calls/struct/winsize.internal.h index 2558b874c..423db93c9 100644 --- a/libc/calls/struct/winsize.internal.h +++ b/libc/calls/struct/winsize.internal.h @@ -8,7 +8,7 @@ COSMOPOLITAN_C_START_ int tcgetwinsize_nt(struct Fd *, struct winsize *); const char *DescribeWinsize(char[64], int, struct winsize *); -#define DescribeWinsize(rc, ws) DescribeWinsize(alloca(12), rc, ws) +#define DescribeWinsize(rc, ws) DescribeWinsize(alloca(64), rc, ws) COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/elf/findelfsectionbyname.c b/libc/elf/findelfsectionbyname.c index c70516afc..5d5a6878a 100644 --- a/libc/elf/findelfsectionbyname.c +++ b/libc/elf/findelfsectionbyname.c @@ -33,11 +33,13 @@ Elf64_Shdr *FindElfSectionByName(Elf64_Ehdr *elf, size_t mapsize, long i; Elf64_Shdr *shdr; const char *secname; - for (i = 0; i < elf->e_shnum; ++i) { - if ((shdr = GetElfSectionHeaderAddress(elf, mapsize, i)) && - (secname = GetElfString(elf, mapsize, shdrstrtab, shdr->sh_name)) && - !strcmp(name, secname)) { - return shdr; + if (shdrstrtab) { + for (i = 0; i < elf->e_shnum; ++i) { + if ((shdr = GetElfSectionHeaderAddress(elf, mapsize, i)) && + (secname = GetElfString(elf, mapsize, shdrstrtab, shdr->sh_name)) && + !strcmp(name, secname)) { + return shdr; + } } } return 0; diff --git a/libc/intrin/restorewintty.c b/libc/intrin/restorewintty.c index 08f924968..e77070891 100644 --- a/libc/intrin/restorewintty.c +++ b/libc/intrin/restorewintty.c @@ -20,6 +20,7 @@ #include "libc/nt/console.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" +#include "libc/nt/thunk/msabi.h" #include "libc/runtime/internal.h" __msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId; @@ -28,17 +29,18 @@ __msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle; extern uint32_t __pid_exec; -const unsigned char kConsoleHandles[3] = { +const signed char kConsoleHandles[3] = { kNtStdInputHandle, kNtStdOutputHandle, kNtStdErrorHandle, }; // Puts cmd.exe gui back the way it was. -privileged dontinstrument void _restorewintty(void) { +void _restorewintty(void) { + int i; if (!IsWindows()) return; if (__imp_GetCurrentProcessId() != __pid_exec) return; - for (int i = 0; i < 3; ++i) { + for (i = 0; i < 3; ++i) { __imp_SetConsoleMode(__imp_GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]); } diff --git a/libc/log/oncrash_arm64.c b/libc/log/oncrash_arm64.c index 8d9b9ede8..8a6249416 100644 --- a/libc/log/oncrash_arm64.c +++ b/libc/log/oncrash_arm64.c @@ -32,10 +32,12 @@ #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/runtime.h" #include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" +#include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/sig.h" #include "libc/thread/thread.h" @@ -162,6 +164,17 @@ static bool AppendFileLine(struct Buffer *b, const char *addr2line, } } +static 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; +} + relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { char buf[10000]; ucontext_t *ctx = arg; @@ -200,6 +213,8 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { if (ctx) { long pc; char line[256]; + char *mem = 0; + size_t memsz = 0; int addend, symbol; const char *debugbin; const char *addr2line; @@ -253,8 +268,7 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { if (pc && st && (symbol = __get_symbol(st, pc))) { addend = pc - st->addr_base; addend -= st->symbols[symbol].x; - Append(b, " "); - Append(b, "%s", __get_symbol_name(st, symbol)); + Append(b, " %s", GetSymbolName(st, symbol, &mem, &memsz)); if (addend) Append(b, "%+d", addend); } Append(b, "\n"); @@ -274,7 +288,7 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { addend -= st->symbols[symbol].x; Append(b, " "); if (!AppendFileLine(b, addr2line, debugbin, pc)) { - Append(b, "%s", __get_symbol_name(st, symbol)); + Append(b, "%s", GetSymbolName(st, symbol, &mem, &memsz)); if (addend) Append(b, "%+d", addend); } } @@ -313,11 +327,12 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { } Append(b, " %016lx fp %lx lr ", fp, pc); if (!AppendFileLine(b, addr2line, debugbin, pc) && st) { - Append(b, "%s", __get_symbol_name(st, symbol)); + Append(b, "%s", GetSymbolName(st, symbol, &mem, &memsz)); if (addend) Append(b, "%+d", addend); } Append(b, "\n"); } + free(mem); } } else { Append(b, "got %G while crashing! pc %lx lr %lx\n", sig, diff --git a/libc/nt/struct/imageoptionalheader.internal.h b/libc/nt/struct/imageoptionalheader.internal.h index db526f04e..29cf9a14f 100644 --- a/libc/nt/struct/imageoptionalheader.internal.h +++ b/libc/nt/struct/imageoptionalheader.internal.h @@ -4,8 +4,20 @@ #include "libc/nt/struct/imagedatadirectory.internal.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) +/** + * Portable Executable Optional Header. + * + * @see NtImageNtHeaders which encloses this + * @see NtImageFileHeader which precedes this + * @see NtImageSectionHeader which follows this + */ struct NtImageOptionalHeader { + + /* + * Must be kNtPe64bit. + */ uint16_t Magic; + uint8_t MajorLinkerVersion; uint8_t MinorLinkerVersion; uint32_t SizeOfCode; @@ -55,8 +67,20 @@ struct NtImageOptionalHeader { uint16_t MajorSubsystemVersion; uint16_t MinorSubsystemVersion; uint32_t Win32VersionValue; + + /* + * The size (in bytes) of the image, including all headers, as the + * image is loaded in memory. It must be a multiple of + * SectionAlignment. + */ uint32_t SizeOfImage; + + /* + * The combined size of an MS-DOS stub, PE header, and section headers + * rounded up to a multiple of FileAlignment. + */ uint32_t SizeOfHeaders; + uint32_t CheckSum; uint16_t Subsystem; uint16_t DllCharacteristics; diff --git a/libc/runtime/cosmo2.c b/libc/runtime/cosmo2.c index e6585faa5..5df560666 100644 --- a/libc/runtime/cosmo2.c +++ b/libc/runtime/cosmo2.c @@ -21,6 +21,7 @@ #include "libc/dce.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/strace.internal.h" +#include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/runtime/internal.h" @@ -32,6 +33,7 @@ #include "libc/sysv/consts/sig.h" #include "libc/thread/thread.h" #include "libc/thread/tls.h" +#include "third_party/lua/lunix.h" #ifndef __x86_64__ /** @@ -128,11 +130,13 @@ textstartup void cosmo(long *sp, struct Syslib *m1) { _mmi.p = _mmi.s; __mmi_lock_obj._type = PTHREAD_MUTEX_RECURSIVE; - // record provided stack to memory manager + // record system provided stack to memory manager + uintptr_t s = (uintptr_t)sp; + uintptr_t z = GetStackSize() << 1; _mmi.i = 1; - _mmi.p->x = (uintptr_t)GetStackAddr() >> 16; - _mmi.p->y = (uintptr_t)(GetStackAddr() + (GetStackSize() - FRAMESIZE)) >> 16; - _mmi.p->size = GetStackSize(); + _mmi.p->x = (s & -z) >> 16; + _mmi.p->y = MIN(((s & -z) + (z - 1)) >> 16, INT_MAX); + _mmi.p->size = z; _mmi.p->prot = PROT_READ | PROT_WRITE; __virtualmax = -1; diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index c77b519e0..e55ccb736 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -66,7 +66,7 @@ __msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; */ extern int64_t __wincrashearly; -extern const char kConsoleHandles[3]; +extern const signed char kConsoleHandles[3]; extern void cosmo(int, char **, char **, long (*)[2]) wontreturn; static const short kConsoleModes[3] = { diff --git a/libc/sock/goodsocket.c b/libc/sock/goodsocket.c index 6ead34788..6a17f358d 100644 --- a/libc/sock/goodsocket.c +++ b/libc/sock/goodsocket.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timeval.h" +#include "libc/errno.h" #include "libc/sock/goodsocket.internal.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/so.h" @@ -33,18 +34,23 @@ static bool Tune(int fd, int a, int b, int x) { */ int GoodSocket(int family, int type, int protocol, bool isserver, const struct timeval *timeout) { - int fd; + int e, fd; if ((fd = socket(family, type, protocol)) != -1) { + e = errno; if (isserver) { Tune(fd, SOL_TCP, TCP_FASTOPEN, 100); Tune(fd, SOL_SOCKET, SO_REUSEADDR, 1); } else { Tune(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1); } + errno = e; if (!Tune(fd, SOL_TCP, TCP_QUICKACK, 1)) { + e = errno; Tune(fd, SOL_TCP, TCP_NODELAY, 1); + errno = e; } if (timeout) { + e = errno; if (timeout->tv_sec < 0) { Tune(fd, SOL_SOCKET, SO_KEEPALIVE, 1); Tune(fd, SOL_TCP, TCP_KEEPIDLE, -timeout->tv_sec); @@ -53,6 +59,7 @@ int GoodSocket(int family, int type, int protocol, bool isserver, setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, timeout, sizeof(*timeout)); } + errno = e; } } return fd; diff --git a/libc/sysv/consts/rlimit.h b/libc/sysv/consts/rlimit.h index d2703ce44..f5db40b22 100644 --- a/libc/sysv/consts/rlimit.h +++ b/libc/sysv/consts/rlimit.h @@ -45,7 +45,6 @@ extern const unsigned RLIMIT_VMEM; #define RLIMIT_SWAP RLIMIT_SWAP #define RLIMIT_VMEM RLIMIT_VMEM - COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_RLIMIT_H_ */ diff --git a/net/https/generatehardrandom.c b/net/https/generatehardrandom.c index e3e5682dd..0f2c2fcb6 100644 --- a/net/https/generatehardrandom.c +++ b/net/https/generatehardrandom.c @@ -16,10 +16,15 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/stdio/rand.h" #include "net/https/https.h" int GenerateHardRandom(void *ctx, unsigned char *p, size_t n) { - rngset(p, n, rdseed, 0); + size_t i; + ssize_t rc; + for (i = 0; i < n; i += (size_t)rc) { + _npassert((rc = getrandom(p + i, n - i, 0)) != -1); + } return 0; } diff --git a/net/turfwar/turfwar.c b/net/turfwar/turfwar.c index 9a4f7ce67..cff1d133d 100644 --- a/net/turfwar/turfwar.c +++ b/net/turfwar/turfwar.c @@ -1929,7 +1929,7 @@ int main(int argc, char *argv[]) { CHECK_EQ(0, chdir("/opt/turfwar")); putenv("TMPDIR=/opt/turfwar/tmp"); - if ((g_blackhole.fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1) { + if ((g_blackhole.fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { kprintf("error: socket(AF_UNIX) failed: %s\n", strerror(errno)); _Exit(3); } diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index 4d1b986a9..5160e84fb 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -33,6 +33,7 @@ #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" +#include "libc/runtime/sysconf.h" #include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" @@ -91,6 +92,17 @@ TEST(mmap, noreplaceExistingMap) { EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); } +TEST(mmap, smallerThanPage_mapsRemainder) { + long pagesz = sysconf(_SC_PAGESIZE); + char *map = mmap(0, 1, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_NE(MAP_FAILED, map); + EXPECT_TRUE(testlib_memoryexists(map)); + EXPECT_TRUE(testlib_memoryexists(map + (pagesz - 1))); + EXPECT_SYS(0, 0, munmap(map, 1)); + EXPECT_FALSE(testlib_memoryexists(map)); + EXPECT_FALSE(testlib_memoryexists(map + (pagesz - 1))); +} + TEST(mmap, testMapFile) { int fd; char *p; diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 989699de2..19da60bb9 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -143,7 +143,7 @@ STATIC_STACK_SIZE(0x80000); STATIC_YOINK("zipos"); -#ifndef TINY +#ifdef USE_BLINK STATIC_YOINK("blink_linux_aarch64"); // for raspberry pi STATIC_YOINK("blink_xnu_aarch64"); // is apple silicon #endif @@ -4928,7 +4928,7 @@ static int LuaProgramTokenBucket(lua_State *L) { blackhole.addr.sun_family = AF_UNIX; strlcpy(blackhole.addr.sun_path, "/var/run/blackhole.sock", sizeof(blackhole.addr.sun_path)); - if ((blackhole.fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1) { + if ((blackhole.fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { WARNF("(token) socket(AF_UNIX) failed: %m"); ban = -1; } else if (sendto(blackhole.fd, &testip, 4, 0,