mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 08:12:28 +00:00
Make fixes and improvements
- Invent iso8601us() for faster timestamps - Improve --strace descriptions of sigset_t - Rebuild the Landlock Make bootstrap binary - Introduce MODE=sysv for non-Windows builds - Permit OFD fcntl() locks under pledge(flock) - redbean can now protect your kernel from ddos - Have vfork() fallback to sys_fork() not fork() - Change kmalloc() to not die when out of memory - Improve documentation for some termios functions - Rewrite putenv() and friends to conform to POSIX - Fix linenoise + strace verbosity issue on Windows - Fix regressions in our ability to show backtraces - Change redbean SetHeader() to no-op if value is nil - Improve fcntl() so SQLite locks work in non-WAL mode - Remove some unnecessary work during fork() on Windows - Create redbean-based SSL reverse proxy for IPv4 TurfWar - Fix ape/apeinstall.sh warning when using non-bash shells - Add ProgramTrustedIp(), and IsTrustedIp() APIs to redbean - Support $PWD, $UID, $GID, and $EUID in command interpreter - Introduce experimental JTqFpD APE prefix for non-Windows builds - Invent blackhole daemon for firewalling IP addresses via UNIX named socket - Add ProgramTokenBucket(), AcquireToken(), and CountTokens() APIs to redbean
This commit is contained in:
parent
648bf6555c
commit
f7ff77d865
209 changed files with 3818 additions and 998 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -55,11 +56,6 @@
|
|||
#define TOMBSTONE ((char *)-1)
|
||||
#define READ24(s) READ32LE(s "\0")
|
||||
|
||||
struct Env {
|
||||
char *s;
|
||||
int i;
|
||||
};
|
||||
|
||||
static char *p;
|
||||
static char *q;
|
||||
static char *r;
|
||||
|
@ -71,7 +67,7 @@ static char *assign;
|
|||
static char var[32];
|
||||
static int lastchild;
|
||||
static int exitstatus;
|
||||
static char *envs[3000];
|
||||
static char *envs[500];
|
||||
static char *args[3000];
|
||||
static const char *prog;
|
||||
static char errbuf[512];
|
||||
|
@ -148,27 +144,9 @@ static int GetSignalByName(const char *s) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct Env GetEnv(char **p, const char *k) {
|
||||
int i, j;
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!k[j] || k[j] == '=') {
|
||||
if (p[i][j] == '=') {
|
||||
return (struct Env){p[i] + j + 1, i};
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (toupper(k[j] & 255) != toupper(p[i][j] & 255)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (struct Env){0, i};
|
||||
}
|
||||
|
||||
static void PutEnv(char **p, const char *kv) {
|
||||
struct Env e;
|
||||
e = GetEnv(p, kv);
|
||||
e = _getenv(p, kv);
|
||||
p[e.i] = kv;
|
||||
if (!e.s) p[e.i + 1] = 0;
|
||||
}
|
||||
|
@ -271,7 +249,7 @@ static int Read(void) {
|
|||
|
||||
static int Cd(void) {
|
||||
const char *s;
|
||||
if ((s = n > 1 ? args[1] : GetEnv(envs, "HOME").s)) {
|
||||
if ((s = n > 1 ? args[1] : _getenv(envs, "HOME").s)) {
|
||||
if (!chdir(s)) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -489,14 +467,27 @@ static const char *IntToStr(int x) {
|
|||
}
|
||||
|
||||
static const char *GetVar(const char *key) {
|
||||
static char vbuf[PATH_MAX];
|
||||
if (key[0] == '$' && !key[1]) {
|
||||
return IntToStr(getpid());
|
||||
} else if (key[0] == '!' && !key[1]) {
|
||||
return IntToStr(lastchild);
|
||||
} else if (key[0] == '?' && !key[1]) {
|
||||
return IntToStr(exitstatus);
|
||||
} else if (!strcmp(key, "PWD")) {
|
||||
_npassert(getcwd(vbuf, sizeof(vbuf)));
|
||||
return vbuf;
|
||||
} else if (!strcmp(key, "UID")) {
|
||||
FormatInt32(vbuf, getuid());
|
||||
return vbuf;
|
||||
} else if (!strcmp(key, "GID")) {
|
||||
FormatInt32(vbuf, getgid());
|
||||
return vbuf;
|
||||
} else if (!strcmp(key, "EUID")) {
|
||||
FormatInt32(vbuf, geteuid());
|
||||
return vbuf;
|
||||
} else {
|
||||
return GetEnv(envs, key).s;
|
||||
return _getenv(envs, key).s;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/morph.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
|
@ -30,7 +32,8 @@ extern int __threadcalls_start[];
|
|||
#pragma weak __threadcalls_end
|
||||
|
||||
static privileged dontinline void FixupLockNops(void) {
|
||||
__morph_begin();
|
||||
sigset_t mask;
|
||||
__morph_begin(&mask);
|
||||
/*
|
||||
* _NOPL("__threadcalls", func)
|
||||
*
|
||||
|
@ -54,7 +57,7 @@ static privileged dontinline void FixupLockNops(void) {
|
|||
_base[*p + 1] = 0x67;
|
||||
_base[*p + 2] = 0xe8;
|
||||
}
|
||||
__morph_end();
|
||||
__morph_end(&mask);
|
||||
}
|
||||
|
||||
void __enable_threads(void) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "libc/nexgen32e/msr.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/morph.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdalign.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -196,9 +198,10 @@ privileged void __enable_tls(void) {
|
|||
if ((intptr_t)_tls_content && (IsWindows() || IsXnu())) {
|
||||
int n;
|
||||
uint64_t w;
|
||||
sigset_t mask;
|
||||
unsigned m, dis;
|
||||
unsigned char *p;
|
||||
__morph_begin();
|
||||
__morph_begin(&mask);
|
||||
|
||||
if (IsXnu()) {
|
||||
// Apple is quite straightforward to patch. We basically
|
||||
|
@ -262,7 +265,7 @@ privileged void __enable_tls(void) {
|
|||
}
|
||||
}
|
||||
|
||||
__morph_end();
|
||||
__morph_end(&mask);
|
||||
}
|
||||
|
||||
// we are now allowed to use tls
|
||||
|
|
|
@ -224,9 +224,6 @@ textwindows void WinMainForked(void) {
|
|||
AbortFork("CloseHandle");
|
||||
}
|
||||
|
||||
// turn tls back on
|
||||
__enable_tls();
|
||||
|
||||
// rewrap the stdin named pipe hack
|
||||
// since the handles closed on fork
|
||||
struct Fds *fds = VEIL("r", &g_fds);
|
||||
|
@ -267,11 +264,14 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
uint32_t oldprot;
|
||||
char **args, **args2;
|
||||
char16_t pipename[64];
|
||||
bool needtls, threaded;
|
||||
int64_t reader, writer;
|
||||
struct NtStartupInfo startinfo;
|
||||
int i, n, pid, untrackpid, rc = -1;
|
||||
char *p, forkvar[6 + 21 + 1 + 21 + 1];
|
||||
struct NtProcessInformation procinfo;
|
||||
threaded = __threaded;
|
||||
needtls = __tls_enabled;
|
||||
if (!setjmp(jb)) {
|
||||
pid = untrackpid = __reservefd_unlocked(-1);
|
||||
reader = CreateNamedPipe(CreatePipeName(pipename),
|
||||
|
@ -345,9 +345,15 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
if (needtls) {
|
||||
__enable_tls();
|
||||
}
|
||||
if (threaded && !__threaded && _weaken(__enable_threads)) {
|
||||
_weaken(__enable_threads)();
|
||||
}
|
||||
}
|
||||
if (untrackpid != -1) {
|
||||
__releasefd_unlocked(untrackpid);
|
||||
__releasefd(untrackpid);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,14 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
/**
|
||||
* Removes all environment variables.
|
||||
*/
|
||||
int clearenv(void) {
|
||||
STRACE("clearenv() → 0");
|
||||
environ = NULL;
|
||||
return 0;
|
||||
int sys_fork(void) {
|
||||
axdx_t ad;
|
||||
int ax, dx;
|
||||
ad = __sys_fork();
|
||||
ax = ad.ax;
|
||||
dx = ad.dx;
|
||||
if (IsXnu() && ax != -1) {
|
||||
// eax always returned with childs pid
|
||||
// edx is 0 for parent and 1 for child
|
||||
ax &= dx - 1;
|
||||
}
|
||||
return ax;
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
|
@ -33,30 +34,15 @@
|
|||
#include "libc/thread/tls.h"
|
||||
|
||||
int _fork(uint32_t dwCreationFlags) {
|
||||
axdx_t ad;
|
||||
bool threaded;
|
||||
sigset_t old, all;
|
||||
int ax, dx, parent;
|
||||
sigfillset(&all);
|
||||
_unassert(!sigprocmask(SIG_BLOCK, &all, &old));
|
||||
BLOCK_SIGNALS;
|
||||
if (__threaded && _weaken(_pthread_onfork_prepare)) {
|
||||
_weaken(_pthread_onfork_prepare)();
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
ad = sys_fork();
|
||||
ax = ad.ax;
|
||||
dx = ad.dx;
|
||||
if (IsXnu() && ax != -1) {
|
||||
// eax always returned with childs pid
|
||||
// edx is 0 for parent and 1 for child
|
||||
ax &= dx - 1;
|
||||
}
|
||||
ax = sys_fork();
|
||||
} else {
|
||||
threaded = __threaded;
|
||||
ax = sys_fork_nt(dwCreationFlags);
|
||||
if (threaded && !__threaded && _weaken(__enable_threads)) {
|
||||
_weaken(__enable_threads)();
|
||||
}
|
||||
}
|
||||
if (!ax) {
|
||||
if (!IsWindows()) {
|
||||
|
@ -81,7 +67,7 @@ int _fork(uint32_t dwCreationFlags) {
|
|||
}
|
||||
STRACE("fork() → %d% m", ax);
|
||||
}
|
||||
_unassert(!sigprocmask(SIG_SETMASK, &old, 0));
|
||||
ALLOW_SIGNALS;
|
||||
return ax;
|
||||
}
|
||||
|
||||
|
@ -92,6 +78,7 @@ int _fork(uint32_t dwCreationFlags) {
|
|||
* @raise EAGAIN if `RLIMIT_NPROC` was exceeded or system lacked resources
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int fork(void) {
|
||||
return _fork(0);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/runtime/morph.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
|
@ -45,13 +46,13 @@ privileged noinstrument noasan int __hook(void *ifunc,
|
|||
size_t i;
|
||||
char *p, *pe;
|
||||
intptr_t addr;
|
||||
sigset_t mask;
|
||||
uint64_t code, mcode;
|
||||
sigset_t mask, oldmask;
|
||||
intptr_t kMcount = (intptr_t)&mcount;
|
||||
intptr_t kProgramCodeStart = (intptr_t)_ereal;
|
||||
intptr_t kPrivilegedStart = (intptr_t)__privileged_addr;
|
||||
if (!symbols) return -1;
|
||||
__morph_begin();
|
||||
__morph_begin(&mask);
|
||||
for (i = 0; i < symbols->count; ++i) {
|
||||
if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) {
|
||||
continue;
|
||||
|
@ -112,6 +113,6 @@ privileged noinstrument noasan int __hook(void *ifunc,
|
|||
}
|
||||
}
|
||||
}
|
||||
__morph_end();
|
||||
__morph_end(&mask);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -135,39 +135,39 @@ forceinline pureconst bool IsFixedFrame(int x) {
|
|||
}
|
||||
|
||||
forceinline pureconst bool OverlapsImageSpace(const void *p, size_t n) {
|
||||
const unsigned char *start, *ender;
|
||||
const unsigned char *BegA, *EndA, *BegB, *EndB;
|
||||
if (n) {
|
||||
start = p;
|
||||
ender = start + (n - 1);
|
||||
return ((_base <= start && start < _end) ||
|
||||
(_base <= ender && ender < _end) ||
|
||||
(start < _base && _end <= ender));
|
||||
BegA = p;
|
||||
EndA = BegA + (n - 1);
|
||||
BegB = _base;
|
||||
EndB = _end - 1;
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline pureconst bool OverlapsArenaSpace(const void *p, size_t n) {
|
||||
intptr_t x, y;
|
||||
intptr_t BegA, EndA, BegB, EndB;
|
||||
if (n) {
|
||||
x = (intptr_t)p;
|
||||
y = x + (n - 1);
|
||||
return ((0x50000000 <= x && x <= 0x7ffdffff) ||
|
||||
(0x50000000 <= y && y <= 0x7ffdffff) ||
|
||||
(x < 0x50000000 && 0x7ffdffff < y));
|
||||
BegA = (intptr_t)p;
|
||||
EndA = BegA + (n - 1);
|
||||
BegB = 0x50000000;
|
||||
EndB = 0x7ffdffff;
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline pureconst bool OverlapsShadowSpace(const void *p, size_t n) {
|
||||
intptr_t x, y;
|
||||
intptr_t BegA, EndA, BegB, EndB;
|
||||
if (n) {
|
||||
x = (intptr_t)p;
|
||||
y = x + (n - 1);
|
||||
return ((0x7fff0000 <= x && x <= 0x10007fffffff) ||
|
||||
(0x7fff0000 <= y && y <= 0x10007fffffff) ||
|
||||
(x < 0x7fff0000 && 0x10007fffffff < y));
|
||||
BegA = (intptr_t)p;
|
||||
EndA = BegA + (n - 1);
|
||||
BegB = 0x7fff0000;
|
||||
EndB = 0x10007fffffff;
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -37,9 +38,6 @@
|
|||
|
||||
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
|
||||
static int64_t vector;
|
||||
static sigset_t oldss;
|
||||
|
||||
static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
||||
int ntprot) {
|
||||
bool cf;
|
||||
|
@ -58,7 +56,7 @@ static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
|||
_Exit(26);
|
||||
}
|
||||
#endif
|
||||
if (ax) notpossible;
|
||||
_npassert(!ax);
|
||||
} else {
|
||||
__imp_VirtualProtect(addr, size, ntprot, &op);
|
||||
}
|
||||
|
@ -69,29 +67,26 @@ static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
|||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
privileged void __morph_begin(void) {
|
||||
privileged void __morph_begin(sigset_t *save) {
|
||||
int ax;
|
||||
bool cf;
|
||||
intptr_t dx;
|
||||
sigset_t ss = {{-1, -1}};
|
||||
STRACE("__morph_begin()");
|
||||
if (!IsWindows()) {
|
||||
if (!IsOpenbsd()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(&ss),
|
||||
"1"(&oldss)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
if (ax) notpossible;
|
||||
} else {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(-1u)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
oldss.__bits[0] = ax & 0xffffffff;
|
||||
if (cf) notpossible;
|
||||
}
|
||||
if (IsOpenbsd()) {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(-1u)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
save->__bits[0] = ax & 0xffffffff;
|
||||
_npassert(!cf);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_BLOCK), "S"(&ss), "1"(save)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
_npassert(!ax);
|
||||
}
|
||||
__morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_WRITE,
|
||||
kNtPageWritecopy);
|
||||
|
@ -100,29 +95,25 @@ privileged void __morph_begin(void) {
|
|||
/**
|
||||
* Begins code morphing executable.
|
||||
*/
|
||||
privileged void __morph_end(void) {
|
||||
privileged void __morph_end(sigset_t *save) {
|
||||
int ax;
|
||||
long dx;
|
||||
bool cf;
|
||||
__morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_EXEC,
|
||||
kNtPageExecuteRead);
|
||||
if (!IsWindows()) {
|
||||
if (!IsOpenbsd()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_SETMASK), "S"(&oldss),
|
||||
"1"(0)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
if (ax) notpossible;
|
||||
} else {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_SETMASK),
|
||||
"S"(oldss.__bits[0])
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
if (cf) notpossible;
|
||||
}
|
||||
if (IsOpenbsd()) {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(ax), "=d"(dx)
|
||||
: "1"(__NR_sigprocmask), "D"(SIG_SETMASK), "S"(save->__bits[0])
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
_npassert(!cf);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
asm volatile("mov\t$8,%%r10d\n\t"
|
||||
"syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_sigprocmask), "D"(SIG_SETMASK), "S"(save), "1"(0)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
_npassert(!ax);
|
||||
}
|
||||
STRACE("__morph_end()");
|
||||
}
|
||||
|
|
12
libc/runtime/morph.h
Normal file
12
libc/runtime/morph.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MORPH_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_MORPH_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void __morph_begin(sigset_t *);
|
||||
void __morph_end(sigset_t *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MORPH_H_ */
|
|
@ -57,7 +57,7 @@ int atfork(void *, void *) libcesque;
|
|||
int atexit(void (*)(void)) libcesque;
|
||||
char *getenv(const char *) nosideeffect libcesque;
|
||||
int putenv(char *) paramsnonnull();
|
||||
int setenv(const char *, const char *, int) paramsnonnull();
|
||||
int setenv(const char *, const char *, int);
|
||||
int unsetenv(const char *);
|
||||
int clearenv(void);
|
||||
void fpreset(void);
|
||||
|
@ -100,8 +100,6 @@ char *GetInterpreterExecutableName(char *, size_t);
|
|||
void __printargs(const char *);
|
||||
void __paginate(int, const char *);
|
||||
int __arg_max(void);
|
||||
void __morph_begin(void);
|
||||
void __morph_end(void);
|
||||
void __print_maps(void);
|
||||
void __warn_if_powersave(void);
|
||||
const char *__describe_os(void);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
@ -29,7 +31,7 @@ textstartup int __strace_init(int argc, char **argv, char **envp, long *auxv) {
|
|||
/* asan isn't initialized yet at runlevel 300 */
|
||||
if (__intercept_flag(&argc, argv, "--strace") ||
|
||||
__atoul(nulltoempty(__getenv(envp, "STRACE")))) {
|
||||
++__strace;
|
||||
atomic_store_explicit(&__strace, 1, memory_order_relaxed);
|
||||
}
|
||||
return (__argc = argc);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/macros.internal.h"
|
||||
.privileged
|
||||
|
||||
// Forks process without copying page tables.
|
||||
//
|
||||
|
@ -32,37 +31,55 @@
|
|||
// do anything in a vfork()'d child process. TLS memory must not
|
||||
// be disabled (it's enabled by default) since vfork() needs it.
|
||||
//
|
||||
// What makes vfork() dangerous is that any changes to memory in
|
||||
// the child process can happen in the parent too. The exception
|
||||
// to this rule is `errno` which is saved/restored in a register
|
||||
// by this implementation. However, despite its dangers, vfork's
|
||||
// performance is irresistible and wonderous to behold. If safer
|
||||
// code is desired, consider posix_spawn() which uses vfork().
|
||||
//
|
||||
// Do not make the assumption that the parent is suspended until
|
||||
// the child terminates since this impl calls fork() on Windows,
|
||||
// OpenBSD, and MacOS.
|
||||
// the child terminates since this uses the raw fork system call
|
||||
// on Windows, OpenBSD, and MacOS. In that case the process will
|
||||
// proceed without blocking the parent; however, the `__vforked`
|
||||
// variable is still set to true in the child, so lock functions
|
||||
// won't do anything, and other functions shall change behavior.
|
||||
// This ensures that, even if the operating system does not give
|
||||
// us the performance of vfork(), we'll still be able to cut out
|
||||
// the libc overhead, e.g. pthread_atfork().
|
||||
//
|
||||
// @return pid of child process or 0 if forked process
|
||||
// @returnstwice
|
||||
// @threadsafe
|
||||
// @vforksafe
|
||||
vfork: call __require_tls
|
||||
xor %edi,%edi # dwCreationFlags
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
jmp fork # TODO: asan and vfork don't mix?
|
||||
.endfn vfork,globl
|
||||
#else
|
||||
#if SupportsWindows()
|
||||
testb IsWindows()
|
||||
jnz sys_fork_nt # and we're lucky to have that
|
||||
#endif
|
||||
#if SupportsXnu()
|
||||
testb IsXnu()
|
||||
jnz fork
|
||||
#endif
|
||||
#if SupportsOpenbsd()
|
||||
testb IsOpenbsd()
|
||||
jnz fork # fake vfork plus msyscall issues
|
||||
#endif
|
||||
vfork:
|
||||
#if !IsTiny()
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
call __require_tls
|
||||
#ifdef SYSDEBUG
|
||||
ezlea .Llog,di
|
||||
call __stracef
|
||||
#endif /* SYSDEBUG */
|
||||
#endif
|
||||
pop %rbp
|
||||
#endif
|
||||
mov %fs:0,%r9 # get thread information block
|
||||
#if SupportsWindows()
|
||||
testb IsWindows()
|
||||
jnz 6f # and we're lucky to have that
|
||||
#endif
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
jmp 5f # TODO: asan and vfork don't mix?
|
||||
#endif
|
||||
#if SupportsXnu()
|
||||
testb IsXnu()
|
||||
jnz 5f
|
||||
#endif
|
||||
#if SupportsOpenbsd()
|
||||
testb IsOpenbsd()
|
||||
jnz 5f # fake vfork plus msyscall issues
|
||||
#endif
|
||||
mov 0x3c(%r9),%r8d # avoid question of @vforksafe errno
|
||||
pop %rsi # saves return address in a register
|
||||
mov __NR_vfork(%rip),%eax
|
||||
|
@ -79,12 +96,35 @@ vfork: call __require_tls
|
|||
cmp $-4095,%eax
|
||||
jae systemfive_error
|
||||
mov %r8d,0x3c(%r9) # restore errno
|
||||
test %eax,%eax
|
||||
jnz .Lprnt
|
||||
.Lchld: orb $TIB_FLAG_VFORKED,0x40(%r9)
|
||||
1: test %eax,%eax
|
||||
jnz .Lpar
|
||||
.Lchi: orb $TIB_FLAG_VFORKED,0x40(%r9)
|
||||
ret
|
||||
.Lprnt: andb $~TIB_FLAG_VFORKED,0x40(%r9)
|
||||
.Lpar: andb $~TIB_FLAG_VFORKED,0x40(%r9)
|
||||
ret
|
||||
#if SupportsXnu() || SupportsOpenbsd() || defined(__SANITIZE_ADDRESS__)
|
||||
5: push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %r9
|
||||
push %r9
|
||||
call sys_fork
|
||||
pop %r9
|
||||
pop %r9
|
||||
pop %rbp
|
||||
jmp 1b
|
||||
#endif
|
||||
#if SupportsWindows()
|
||||
6: push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %r9
|
||||
push %r9
|
||||
xor %edi,%edi # dwCreationFlags
|
||||
call sys_fork_nt
|
||||
pop %r9
|
||||
pop %r9
|
||||
pop %rbp
|
||||
jmp 1b
|
||||
#endif
|
||||
.endfn vfork,globl
|
||||
|
||||
#ifdef SYSDEBUG
|
||||
|
@ -93,5 +133,3 @@ vfork: call __require_tls
|
|||
.asciz "vfork()\n"
|
||||
.previous
|
||||
#endif /* DEBUGSYS */
|
||||
|
||||
#endif /* __SANITIZE_ADDRESS__ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue