Avoid leaking handles across processes

This commit is contained in:
Justine Tunney 2023-09-12 01:07:51 -07:00
parent a359de7893
commit 8a0008d985
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
44 changed files with 232 additions and 266 deletions

View file

@ -61,7 +61,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
handle = g_fds.p[oldfd].handle;
proc = GetCurrentProcess();
if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true,
if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, false,
kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].mode = g_fds.p[oldfd].mode;

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/sigaction.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/dce.h"
@ -37,6 +38,7 @@
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
@ -65,6 +67,7 @@
// clang-format off
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(DuplicateHandle) *const __imp_DuplicateHandle;
__msabi extern typeof(ExitProcess) *const __imp_ExitProcess;
__msabi extern typeof(GenerateConsoleCtrlEvent) *const __imp_GenerateConsoleCtrlEvent;
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
@ -72,6 +75,7 @@ __msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess;
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
__msabi extern typeof(OpenThread) *const __imp_OpenThread;
__msabi extern typeof(SetConsoleCtrlHandler) *const __imp_SetConsoleCtrlHandler;
__msabi extern typeof(SetHandleInformation) *const __imp_SetHandleInformation;
__msabi extern typeof(TerminateThread) *const __imp_TerminateThread;
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
@ -171,23 +175,6 @@ keywords int sys_execve_nt(const char *program, char *const argv[],
PurgeThread(*_weaken(__sigchld_thread));
PurgeThread(*_weaken(__sigwinch_thread));
// close win32 handles for memory mappings
// unlike fork calling execve destroys all memory
// closing a map handle won't impact the mapping itself
for (i = 0; i < _mmi.i; ++i) {
PurgeHandle(_mmi.p[i].h);
}
// close o_cloexec fds and anything that isn't stdio
for (i = 0; i < g_fds.n; ++i) {
if (g_fds.p[i].kind == kFdEmpty) {
g_fds.p[i].handle = -1;
} else if (i > 2 || (g_fds.p[i].flags & O_CLOEXEC)) {
PurgeHandle(g_fds.p[i].handle);
g_fds.p[i].handle = -1;
}
}
// pass bitmask telling child which fds are sockets
int bits;
char buf[32], *v = 0;
@ -205,10 +192,16 @@ keywords int sys_execve_nt(const char *program, char *const argv[],
struct NtStartupInfo si = {
.cb = sizeof(struct NtStartupInfo),
.dwFlags = kNtStartfUsestdhandles,
.hStdInput = g_fds.p[0].handle,
.hStdOutput = g_fds.p[1].handle,
.hStdError = g_fds.p[2].handle,
};
for (i = 0; i <= 2; ++i) {
if (g_fds.p[i].kind != kFdEmpty && //
!(g_fds.p[i].flags & O_CLOEXEC)) {
__imp_SetHandleInformation(g_fds.p[i].handle, kNtHandleFlagInherit, true);
si.stdiofds[i] = g_fds.p[i].handle;
} else {
si.stdiofds[i] = -1;
}
}
// launch the process
struct NtProcessInformation pi;
@ -223,6 +216,11 @@ keywords int sys_execve_nt(const char *program, char *const argv[],
}
PurgeHandle(pi.hThread);
// remove duplicate handles
for (i = 0; i <= 2; ++i) {
PurgeHandle(si.stdiofds[i]);
}
// retreat to original win32-provided stack memory
__switch_stacks(pi.hProcess, 0, 0, 0, sys_execve_nt_relay, __oldstack);
}
@ -240,19 +238,25 @@ static keywords void sys_execve_nt_relay(intptr_t h, long b, long c, long d) {
// close more handles
__imp_SetConsoleCtrlHandler((void *)sys_execve_nt_event, 1);
PurgeThread(g_fds.stdin.thread); // wasn't inherited by ntspawn
PurgeHandle(g_fds.stdin.reader); // wasn't inherited by ntspawn
PurgeHandle(g_fds.stdin.writer); // wasn't inherited by ntspawn
PurgeHandle(g_fds.p[0].handle); // was inherited via startinfo
PurgeHandle(g_fds.p[1].handle); // was inherited via startinfo
PurgeHandle(g_fds.p[2].handle); // was inherited via startinfo
PurgeThread(g_fds.stdin.thread);
PurgeHandle(g_fds.stdin.reader);
PurgeHandle(g_fds.stdin.writer);
for (i = 0; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty) {
PurgeHandle(g_fds.p[i].handle);
if (g_fds.p[i].kind == kFdConsole) {
PurgeHandle(g_fds.p[i].extra);
}
}
}
if (_weaken(__klog_handle)) {
PurgeHandle(*_weaken(__klog_handle)); // wasn't inherited by ntspawn
PurgeHandle(*_weaken(__klog_handle));
}
// free all the memory mmap created
for (i = 0; i < _mmi.i; ++i) {
__imp_UnmapViewOfFile((void *)((uintptr_t)_mmi.p[i].x << 16));
PurgeHandle(_mmi.p[i].h);
}
// wait for process to terminate

View file

@ -130,12 +130,11 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
// open the file, following symlinks
int e = errno;
int64_t hand = CreateFile(path16, perm | extra_perm, share, &kNtIsInheritable,
disp, attr | extra_attr, 0);
int64_t hand = CreateFile(path16, perm | extra_perm, share, 0, disp,
attr | extra_attr, 0);
if (hand == -1 && errno == EACCES && (flags & O_ACCMODE) == O_RDONLY) {
errno = e;
hand = CreateFile(path16, perm, share, &kNtIsInheritable, disp,
attr | extra_attr, 0);
hand = CreateFile(path16, perm, share, 0, disp, attr | extra_attr, 0);
}
return __fix_enotdir(hand, path16);

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/handlock.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@ -52,11 +53,11 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
}
__fds_unlock();
hin = CreateNamedPipe(pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped,
mode, 1, PIPE_BUF, PIPE_BUF, 0, &kNtIsInheritable);
mode, 1, PIPE_BUF, PIPE_BUF, 0, 0);
__fds_lock();
if (hin != -1) {
if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable,
kNtOpenExisting, kNtFileFlagOverlapped, 0)) != -1) {
if ((hout = CreateFile(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting,
kNtFileFlagOverlapped, 0)) != -1) {
g_fds.p[reader].kind = kFdFile;
g_fds.p[reader].flags = O_RDONLY | flags;
g_fds.p[reader].mode = 0010444;

View file

@ -33,8 +33,8 @@ textwindows int sys_statfs_nt(const char *path, struct statfs *sf) {
if (__mkntpath(path, path16) == -1) return -1;
h = __fix_enotdir(
CreateFile(path16, kNtFileGenericRead,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
&kNtIsInheritable, kNtOpenExisting,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
kNtOpenExisting,
kNtFileAttributeNormal | kNtFileFlagBackupSemantics, 0),
path16);
if (h == -1) return -1;

View file

@ -28,7 +28,7 @@
* @see System Five Application Binary Interface § 3.4.3
* @asyncsignalsafe
*/
dontasan struct AuxiliaryValue __getauxval(unsigned long at) {
struct AuxiliaryValue __getauxval(unsigned long at) {
unsigned long *ap;
for (ap = __auxv; ap[0]; ap += 2) {
if (at == ap[0]) {

View file

@ -22,7 +22,7 @@
#define ToUpper(c) \
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
dontasan privileged struct Env __getenv(char **p, const char *k) {
privileged struct Env __getenv(char **p, const char *k) {
char *t;
int i, j;
for (i = 0; (t = p[i]); ++i) {

View file

@ -773,7 +773,7 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) {
}
}
static dontasan void __asan_onmemory(void *x, void *y, size_t n, void *a) {
static void __asan_onmemory(void *x, void *y, size_t n, void *a) {
const unsigned char *p = x;
struct ReportOriginHeap *t = a;
if ((p <= t->a && t->a < p + n) ||

View file

@ -25,8 +25,8 @@
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
dontinstrument dontasan const char *(DescribeBacktrace)(char buf[N],
struct StackFrame *fr) {
dontinstrument const char *(DescribeBacktrace)(char buf[N],
struct StackFrame *fr) {
bool gotsome = false;
char *p = buf;
char *pe = p + N;

View file

@ -24,7 +24,6 @@
const char *(
DescribeNtSecurityAttributes)(char buf[32],
const struct NtSecurityAttributes *p) {
if (p == &kNtIsInheritable) return "&kNtIsInheritable";
FormatInt64(buf, (uintptr_t)p);
return buf;
}

View file

@ -32,15 +32,15 @@
static uint64_t sys_mmap_metal_break;
dontasan static struct DirectMap bad_mmap(void) {
static struct DirectMap bad_mmap(void) {
struct DirectMap res;
res.addr = (void *)-1;
res.maphandle = -1;
return res;
}
dontasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot,
int flags, int fd, int64_t off) {
struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
int fd, int64_t off) {
/* asan runtime depends on this function */
size_t i;
struct mman *mm;

View file

@ -42,13 +42,6 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
handle = g_fds.p[fd].handle;
}
const struct NtSecurityAttributes *sec;
if ((flags & MAP_TYPE) != MAP_SHARED) {
sec = 0; // MAP_PRIVATE isn't inherited across fork()
} else {
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
}
// nt will whine under many circumstances if we change the execute bit
// later using mprotect(). the workaround is to always request execute
// and then virtualprotect() it away until we actually need it. please
@ -80,7 +73,7 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
int e = errno;
struct DirectMap dm;
TryAgain:
if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
if ((dm.maphandle = CreateFileMapping(handle, 0, fl.flags1,
(size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
size, addr))) {

View file

@ -32,7 +32,7 @@
#define G FRAMESIZE
static dontasan void *_mapframe(void *p, int f) {
static void *_mapframe(void *p, int f) {
int rc, prot, flags;
struct DirectMap dm;
prot = PROT_READ | PROT_WRITE;
@ -73,7 +73,7 @@ static dontasan void *_mapframe(void *p, int f) {
* @return new value for `e` or null w/ errno
* @raise ENOMEM if we require more vespene gas
*/
dontasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
char *q;
unassert(!((uintptr_t)SHADOW(p) & (G - 1)));
unassert((uintptr_t)p + (G << kAsanScale) <= h);

View file

@ -18,7 +18,7 @@
*/
#include "libc/runtime/memtrack.internal.h"
dontasan unsigned __find_memory(const struct MemoryIntervals *mm, int x) {
unsigned __find_memory(const struct MemoryIntervals *mm, int x) {
unsigned l, m, r;
l = 0;
r = mm->i;

View file

@ -25,7 +25,7 @@
* @param delta is added to enabled state
* @return enabled state before `delta` was applied
*/
dontasan dontubsan dontinstrument int ftrace_enabled(int delta) {
dontinstrument int ftrace_enabled(int delta) {
int res;
struct CosmoTib *tib;
if (__tls_enabled) {

View file

@ -41,7 +41,7 @@
* @threadsafe
* @vforksafe
*/
dontasan int getpid(void) {
int getpid(void) {
int rc;
if (IsMetal()) {
rc = 1;

62
libc/intrin/handlock.c Normal file
View file

@ -0,0 +1,62 @@
/*-*- 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 2023 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
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/intrin/weaken.h"
#include "libc/str/str.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/mu.h"
/**
* @fileoverview r/w lock for maanging windows file inheritence
*/
static nsync_mu __hand_mu;
void __hand_init(void) {
if (!SupportsWindows()) return;
bzero(&__hand_mu, sizeof(__hand_mu));
}
void __hand_rlock(void) {
if (!IsWindows()) return;
if (_weaken(nsync_mu_rlock) && __threaded) {
_weaken(nsync_mu_rlock)(&__hand_mu);
}
}
void __hand_runlock(void) {
if (!IsWindows()) return;
if (_weaken(nsync_mu_runlock) && __threaded) {
_weaken(nsync_mu_runlock)(&__hand_mu);
}
}
void __hand_lock(void) {
if (!IsWindows()) return;
if (_weaken(nsync_mu_lock) && __threaded) {
_weaken(nsync_mu_lock)(&__hand_mu);
}
}
void __hand_unlock(void) {
if (!IsWindows()) return;
if (_weaken(nsync_mu_unlock) && __threaded) {
_weaken(nsync_mu_unlock)(&__hand_mu);
}
}

View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_HANDLOCK_INTERNAL_H_
#define COSMOPOLITAN_LIBC_INTRIN_HANDLOCK_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void __hand_init(void);
void __hand_rlock(void);
void __hand_runlock(void);
void __hand_lock(void);
void __hand_unlock(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_HANDLOCK_INTERNAL_H_ */

View file

@ -46,31 +46,11 @@ $(LIBC_INTRIN_A).pkg: \
$(LIBC_INTRIN_A_OBJS) \
$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg)
# we can't use asan because:
# __strace_init() calls this before asan is initialized
o/$(MODE)/libc/intrin/strace_enabled.o: private \
COPTS += \
-fno-sanitize=address
o/$(MODE)/libc/intrin/mman.greg.o: private COPTS += -Os
# we can't use asan because:
# asan guard pages haven't been allocated yet
o/$(MODE)/libc/intrin/directmap.o \
o/$(MODE)/libc/intrin/directmap-nt.o: private \
COPTS += \
-ffreestanding \
-fno-sanitize=address
# we want small code size because:
# to keep .text.head under 4096 bytes
o/$(MODE)/libc/intrin/mman.greg.o: private \
COPTS += \
-Os
# we can't use asan and ubsan because:
# this is asan and ubsan
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: private \
$(LIBC_INTRIN_A_OBJS): private \
CFLAGS += \
-x-no-pg \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
@ -81,121 +61,6 @@ o/$(MODE)/libc/intrin/asan.o: private \
-finline \
-finline-functions
o/$(MODE)/libc/intrin/asanthunk.o: private \
CFLAGS += \
-x-no-pg \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
# we can't use compiler magic because:
# kprintf() is mission critical to error reporting
o/$(MODE)/libc/intrin/getmagnumstr.greg.o \
o/$(MODE)/libc/intrin/strerrno.greg.o \
o/$(MODE)/libc/intrin/strerrdoc.greg.o \
o/$(MODE)/libc/intrin/strerror_wr.greg.o \
o/$(MODE)/libc/intrin/kprintf.greg.o: private \
CFLAGS += \
-fpie \
-fwrapv \
-x-no-pg \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
# TODO(jart): Do we really need these?
# synchronization primitives are intended to be magic free
o/$(MODE)/libc/intrin/futex_wait.o \
o/$(MODE)/libc/intrin/futex_wake.o \
o/$(MODE)/libc/intrin/gettid.greg.o \
o/$(MODE)/libc/intrin/_trylock_debug_4.o \
o/$(MODE)/libc/intrin/_spinlock_debug_4.o: private \
CFLAGS += \
-fwrapv \
-x-no-pg \
-ffreestanding \
-fno-sanitize=all \
-mgeneral-regs-only \
-fno-stack-protector
# we can't use asan because:
# global gone could be raised
o/$(MODE)/libc/intrin/exit.o \
o/$(MODE)/libc/intrin/restorewintty.o: private \
CFLAGS += \
-fno-sanitize=all
# we can't use -ftrapv because:
# this file implements it
o/$(MODE)/libc/intrin/ftrapv.o: private \
CFLAGS += \
-ffunction-sections \
-ffreestanding \
-fwrapv
# we can't use asan because:
# sys_mmap() calls these which sets up shadow memory
o/$(MODE)/libc/intrin/describeflags.o \
o/$(MODE)/libc/intrin/describeframe.o \
o/$(MODE)/libc/intrin/describemapflags.o \
o/$(MODE)/libc/intrin/describeprotflags.o: private \
CFLAGS += \
-fno-sanitize=address
o/$(MODE)/libc/intrin/exit1.greg.o \
o/$(MODE)/libc/intrin/wsarecv.o \
o/$(MODE)/libc/intrin/wsarecvfrom.o \
o/$(MODE)/libc/intrin/createfile.o \
o/$(MODE)/libc/intrin/reopenfile.o \
o/$(MODE)/libc/intrin/deletefile.o \
o/$(MODE)/libc/intrin/createpipe.o \
o/$(MODE)/libc/intrin/closehandle.o \
o/$(MODE)/libc/intrin/openprocess.o \
o/$(MODE)/libc/intrin/createthread.o \
o/$(MODE)/libc/intrin/findclose.o \
o/$(MODE)/libc/intrin/findnextfile.o \
o/$(MODE)/libc/intrin/createprocess.o \
o/$(MODE)/libc/intrin/findfirstfile.o \
o/$(MODE)/libc/intrin/removedirectory.o \
o/$(MODE)/libc/intrin/createsymboliclink.o \
o/$(MODE)/libc/intrin/createnamedpipe.o \
o/$(MODE)/libc/intrin/unmapviewoffile.o \
o/$(MODE)/libc/intrin/virtualprotect.o \
o/$(MODE)/libc/intrin/flushviewoffile.o \
o/$(MODE)/libc/intrin/createdirectory.o \
o/$(MODE)/libc/intrin/flushfilebuffers.o \
o/$(MODE)/libc/intrin/terminateprocess.o \
o/$(MODE)/libc/intrin/getfileattributes.o \
o/$(MODE)/libc/intrin/getexitcodeprocess.o \
o/$(MODE)/libc/intrin/waitforsingleobject.o \
o/$(MODE)/libc/intrin/setcurrentdirectory.o \
o/$(MODE)/libc/intrin/mapviewoffileex.o \
o/$(MODE)/libc/intrin/movefileex.o \
o/$(MODE)/libc/intrin/mapviewoffileexnuma.o \
o/$(MODE)/libc/intrin/createfilemapping.o \
o/$(MODE)/libc/intrin/createfilemappingnuma.o \
o/$(MODE)/libc/intrin/waitformultipleobjects.o \
o/$(MODE)/libc/intrin/wsagetoverlappedresult.o \
o/$(MODE)/libc/intrin/generateconsolectrlevent.o \
o/$(MODE)/libc/intrin/wsawaitformultipleevents.o: private\
CFLAGS += \
-Os \
-fwrapv \
-ffreestanding \
-fno-stack-protector \
-fno-sanitize=all
# privileged functions
o/$(MODE)/libc/intrin/dos2errno.o \
o/$(MODE)/libc/intrin/have_fsgsbase.o \
o/$(MODE)/libc/intrin/getmagnumstr.o \
o/$(MODE)/libc/intrin/formatint32.o \
o/$(MODE)/libc/intrin/strsignal_r.o \
o/$(MODE)/libc/intrin/strerror_wr.o: private \
CFLAGS += \
-ffreestanding \
-fno-sanitize=all
o//libc/intrin/memmove.o: private \
CFLAGS += \
-fno-toplevel-reorder

View file

@ -32,7 +32,7 @@
#define kBufSize 1024
#define kPid "TracerPid:\t"
static textwindows dontasan bool IsBeingDebugged(void) {
static textwindows bool IsBeingDebugged(void) {
return !!NtGetPeb()->BeingDebugged;
}

View file

@ -36,9 +36,8 @@ static inline const unsigned char *memchr_pure(const unsigned char *s,
}
#if defined(__x86_64__) && !defined(__chibicc__)
dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
unsigned char c,
size_t n) {
static inline const unsigned char *memchr_sse(const unsigned char *s,
unsigned char c, size_t n) {
size_t i;
unsigned m;
xmm_t v, t = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
@ -68,7 +67,7 @@ dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
* @return is pointer to first instance of c or NULL if not found
* @asyncsignalsafe
*/
dontasan void *memchr(const void *s, int c, size_t n) {
void *memchr(const void *s, int c, size_t n) {
#if defined(__x86_64__) && !defined(__chibicc__)
const void *r;
if (IsAsan()) __asan_verify(s, n);

View file

@ -37,9 +37,8 @@ static inline const unsigned char *memrchr_pure(const unsigned char *s,
}
#if defined(__x86_64__) && !defined(__chibicc__)
dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
unsigned char c,
size_t n) {
static inline const unsigned char *memrchr_sse(const unsigned char *s,
unsigned char c, size_t n) {
size_t i;
unsigned m;
xmm_t v, t = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};

View file

@ -54,7 +54,7 @@ struct ReclaimedPage {
/**
* Allocates new page of physical memory.
*/
dontasan texthead uint64_t __new_page(struct mman *mm) {
texthead uint64_t __new_page(struct mman *mm) {
uint64_t p = mm->frp;
if (p != NOPAGE) {
uint64_t q;
@ -81,8 +81,8 @@ dontasan texthead uint64_t __new_page(struct mman *mm) {
* Returns pointer to page table entry for page at virtual address.
* Additional page tables are allocated if needed as a side-effect.
*/
dontasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
int64_t vaddr, bool maketables) {
textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t, int64_t vaddr,
bool maketables) {
uint64_t *e, p;
unsigned char h;
for (h = 39;; h -= 9) {
@ -101,7 +101,7 @@ dontasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
/**
* Sorts, rounds, and filters BIOS memory map.
*/
static dontasan textreal void __normalize_e820(struct mman *mm, uint64_t top) {
static textreal void __normalize_e820(struct mman *mm, uint64_t top) {
uint64_t a, b;
uint64_t x, y;
unsigned i, j, n;
@ -134,10 +134,9 @@ static dontasan textreal void __normalize_e820(struct mman *mm, uint64_t top) {
/**
* Identity maps an area of physical memory to its negative address.
*/
dontasan textreal uint64_t *__invert_memory_area(struct mman *mm,
uint64_t *pml4t, uint64_t ps,
uint64_t size,
uint64_t pte_flags) {
textreal uint64_t *__invert_memory_area(struct mman *mm, uint64_t *pml4t,
uint64_t ps, uint64_t size,
uint64_t pte_flags) {
uint64_t pe = ps + size, p, *m = NULL;
ps = ROUNDDOWN(ps, 4096);
pe = ROUNDUP(pe, 4096);
@ -153,7 +152,7 @@ dontasan textreal uint64_t *__invert_memory_area(struct mman *mm,
/**
* Increments the reference count for a page of physical memory.
*/
dontasan void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
uint64_t *m, e;
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
if (m) {
@ -168,8 +167,7 @@ dontasan void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
/**
* Increments the reference counts for an area of physical memory.
*/
dontasan void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps,
uint64_t size) {
void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps, uint64_t size) {
uint64_t p = ROUNDDOWN(ps, 4096), e = ROUNDUP(ps + size, 4096);
while (p != e) {
__ref_page(mm, pml4t, p);
@ -180,7 +178,7 @@ dontasan void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps,
/**
* Reclaims a page of physical memory for later use.
*/
static dontasan void __reclaim_page(struct mman *mm, uint64_t p) {
static void __reclaim_page(struct mman *mm, uint64_t p) {
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p);
unassert(p == (p & PAGE_TA));
rp->next = mm->frp;
@ -192,7 +190,7 @@ static dontasan void __reclaim_page(struct mman *mm, uint64_t p) {
* page if there are no virtual addresses (excluding the negative space)
* referring to it.
*/
dontasan void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
uint64_t *m, e;
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
if (m) {
@ -208,8 +206,7 @@ dontasan void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
/**
* Identity maps all usable physical memory to its negative address.
*/
static dontasan textreal void __invert_memory(struct mman *mm,
uint64_t *pml4t) {
static textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
uint64_t i;
for (i = 0; i < mm->e820n; ++i) {
uint64_t ps = mm->e820[i].addr, size = mm->e820[i].size;
@ -232,8 +229,7 @@ static dontasan textreal void __invert_memory(struct mman *mm,
: "i"(offsetof(type, member))); \
} while (0)
dontasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t,
uint64_t top) {
textreal void __setup_mman(struct mman *mm, uint64_t *pml4t, uint64_t top) {
export_offsetof(struct mman, pc_drive_base_table);
export_offsetof(struct mman, pc_drive_last_sector);
export_offsetof(struct mman, pc_drive_last_head);
@ -259,8 +255,8 @@ dontasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t,
/**
* Maps APE-defined ELF program headers into memory and clears BSS.
*/
dontasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
uint64_t top) {
textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
uint64_t top) {
uint64_t i, f, v, m;
struct Elf64_Phdr *p;
extern char ape_phdrs[] __attribute__((__weak__));
@ -294,9 +290,8 @@ dontasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
* Reclaims memory pages which were used at boot time but which can now be
* made available for the application.
*/
dontasan textreal void __reclaim_boot_pages(struct mman *mm,
uint64_t skip_start,
uint64_t skip_end) {
textreal void __reclaim_boot_pages(struct mman *mm, uint64_t skip_start,
uint64_t skip_end) {
uint64_t p = mm->frp, q = IMAGE_BASE_REAL, i, n = mm->e820n, b, e;
for (i = 0; i < n; ++i) {
b = mm->e820[i].addr;

View file

@ -48,9 +48,8 @@
*/
bool __nocolor;
optimizesize textstartup dontasan void __nocolor_init(int argc, char **argv,
char **envp,
intptr_t *auxv) {
optimizesize textstartup void __nocolor_init(int argc, char **argv, char **envp,
intptr_t *auxv) {
char *s;
__nocolor = (IsWindows() && !IsAtLeastWindows10()) ||
((s = getenv("TERM")) && IsDumb(s));

View file

@ -27,7 +27,7 @@
*
* @see IsAtLeastWindows10()
*/
textwindows dontasan int NtGetVersion(void) {
textwindows int NtGetVersion(void) {
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
}

View file

@ -33,7 +33,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
* @return pointer to nul byte
* @asyncsignalsafe
*/
dontasan char *stpcpy(char *d, const char *s) {
char *stpcpy(char *d, const char *s) {
size_t i = 0;
if (IsAsan()) {
__asan_verify(d, strlen(s) + 1);

View file

@ -4,11 +4,11 @@
#include "libc/runtime/runtime.h"
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 1 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _STDIOTRACE 0 /* not configurable w/ flag yet */
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %6P %'18T "

View file

@ -25,7 +25,7 @@
* @param delta is added to enabled state
* @return enabled state before `delta` was applied
*/
dontasan dontubsan dontinstrument int strace_enabled(int delta) {
dontinstrument int strace_enabled(int delta) {
int res;
struct CosmoTib *tib;
if (__tls_enabled) {

View file

@ -32,7 +32,7 @@ static inline const char *strchr_pure(const char *s, int c) {
#if defined(__x86_64__) && !defined(__chibicc__)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
dontasan static inline const char *strchr_sse(const char *s, unsigned char c) {
static inline const char *strchr_sse(const char *s, unsigned char c) {
unsigned k;
unsigned m;
const xmm_t *p;
@ -56,7 +56,7 @@ dontasan static inline const char *strchr_sse(const char *s, unsigned char c) {
}
#endif
static dontasan inline const char *strchr_x64(const char *p, uint64_t c) {
static inline const char *strchr_x64(const char *p, uint64_t c) {
unsigned a, b;
uint64_t w, x, y;
for (c *= 0x0101010101010101;; p += 8) {
@ -95,7 +95,7 @@ static dontasan inline const char *strchr_x64(const char *p, uint64_t c) {
* @asyncsignalsafe
* @vforksafe
*/
dontasan char *strchr(const char *s, int c) {
char *strchr(const char *s, int c) {
if (IsAsan()) __asan_verify_str(s);
#if defined(__x86_64__) && !defined(__chibicc__)
const char *r;

View file

@ -32,8 +32,7 @@ static inline const char *strchrnul_pure(const char *s, int c) {
#if defined(__x86_64__) && !defined(__chibicc__)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
dontasan static inline const char *strchrnul_sse(const char *s,
unsigned char c) {
static inline const char *strchrnul_sse(const char *s, unsigned char c) {
unsigned k;
unsigned m;
const xmm_t *p;
@ -54,7 +53,7 @@ dontasan static inline const char *strchrnul_sse(const char *s,
}
#endif
dontasan static const char *strchrnul_x64(const char *p, uint64_t c) {
static const char *strchrnul_x64(const char *p, uint64_t c) {
unsigned a, b;
uint64_t w, x, y;
for (c *= 0x0101010101010101;; p += 8) {

View file

@ -29,7 +29,7 @@
* @return is <0, 0, or >0 based on uint8_t comparison
* @asyncsignalsafe
*/
dontasan int strcmp(const char *a, const char *b) {
int strcmp(const char *a, const char *b) {
int c;
size_t i = 0;
uint64_t v, w;

View file

@ -33,7 +33,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
* @return original dest
* @asyncsignalsafe
*/
dontasan char *strcpy(char *d, const char *s) {
char *strcpy(char *d, const char *s) {
size_t i = 0;
if (IsAsan()) {
__asan_verify_str(s);

View file

@ -25,7 +25,7 @@
// clang-format off
#if defined(SYSDEBUG) && _NTTRACE
dontasan dontubsan privileged
privileged
#endif
/**

View file

@ -30,7 +30,7 @@
// clang-format off
#if defined(SYSDEBUG) && _NTTRACE
dontasan dontubsan privileged
privileged
#endif
/**

View file

@ -28,7 +28,7 @@
* @return number of bytes (excluding NUL)
* @asyncsignalsafe
*/
dontasan size_t strlen(const char *s) {
size_t strlen(const char *s) {
if (IsAsan()) __asan_verify_str(s);
#if defined(__x86_64__) && !defined(__chibicc__)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));

View file

@ -23,7 +23,7 @@
#include "libc/str/str.h"
#ifndef __aarch64__
static dontasan size_t strnlen_x64(const char *s, size_t n, size_t i) {
static size_t strnlen_x64(const char *s, size_t n, size_t i) {
uint64_t w;
for (; i + 8 < n; i += 8) {
w = *(uint64_t *)(s + i);
@ -43,7 +43,7 @@ static dontasan size_t strnlen_x64(const char *s, size_t n, size_t i) {
* @return byte length
* @asyncsignalsafe
*/
dontasan size_t strnlen(const char *s, size_t n) {
size_t strnlen(const char *s, size_t n) {
size_t i;
if (IsAsan() && n) __asan_verify(s, 1);
for (i = 0; (uintptr_t)(s + i) & 7; ++i) {

View file

@ -31,6 +31,6 @@ char *strrchr(const char *s, int c) {
return memrchr(s, c, strlen(s));
}
__strong_reference(strrchr, rindex);
__weak_reference(strrchr, rindex);
#endif /* __aarch64__ */

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/wincrash.internal.h"
@ -26,6 +27,7 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/intrin/handlock.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
@ -43,6 +45,7 @@
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/ipc.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
@ -313,6 +316,21 @@ textwindows void WinMainForked(void) {
longjmp(jb, 1);
}
static void __hand_inherit(bool32 bInherit) {
for (int i = 0; i < _mmi.i; ++i) {
if ((_mmi.p[i].flags & MAP_TYPE) == MAP_SHARED) {
SetHandleInformation(_mmi.p[i].h, kNtHandleFlagInherit, bInherit);
}
}
for (int i = 0; i < g_fds.n; ++i) {
if (g_fds.p[i].kind == kFdEmpty) continue;
SetHandleInformation(g_fds.p[i].handle, kNtHandleFlagInherit, bInherit);
if (g_fds.p[i].kind == kFdConsole) {
SetHandleInformation(g_fds.p[i].extra, kNtHandleFlagInherit, bInherit);
}
}
}
textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
jmp_buf jb;
uint32_t op;
@ -357,8 +375,12 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
args = args2;
}
#endif
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar, 0, 0,
true, dwCreationFlags, 0, &startinfo, &procinfo) != -1) {
__hand_inherit(true);
int spawnrc =
ntspawn(GetProgramExecutableName(), args, environ, forkvar, 0, 0,
true, dwCreationFlags, 0, &startinfo, &procinfo);
__hand_inherit(false);
if (spawnrc != -1) {
CloseHandle(procinfo.hThread);
ok = WriteAll(writer, jb, sizeof(jb)) &&
WriteAll(writer, &_mmi.i, sizeof(_mmi.i)) &&

View file

@ -127,7 +127,7 @@ __msabi static textwindows void DeduplicateStdioHandles(void) {
int64_t h2 = __imp_GetStdHandle(kNtStdio[j]);
if (h1 == h2) {
int64_t h3, proc = __imp_GetCurrentProcess();
__imp_DuplicateHandle(proc, h2, proc, &h3, 0, true,
__imp_DuplicateHandle(proc, h2, proc, &h3, 0, false,
kNtDuplicateSameAccess);
__imp_SetStdHandle(kNtStdio[j], h3);
}
@ -159,11 +159,10 @@ __msabi static textwindows wontreturn void WinInit(const char16_t *cmdline) {
_mmi.n = ARRAYLEN(_mmi.s);
uintptr_t stackaddr = GetStaticStackAddr(0);
size_t stacksize = GetStaticStackSize();
__imp_MapViewOfFileEx((_mmi.p[0].h = __imp_CreateFileMappingW(
-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
stacksize >> 32, stacksize, NULL)),
kNtFileMapWrite | kNtFileMapExecute, 0, 0, stacksize,
(void *)stackaddr);
__imp_MapViewOfFileEx(
(_mmi.p[0].h = __imp_CreateFileMappingW(
-1, 0, kNtPageExecuteReadwrite, stacksize >> 32, stacksize, NULL)),
kNtFileMapWrite | kNtFileMapExecute, 0, 0, stacksize, (void *)stackaddr);
int prot = (intptr_t)ape_stack_prot;
if (~prot & PROT_EXEC) {
uint32_t old;
@ -186,9 +185,8 @@ __msabi static textwindows wontreturn void WinInit(const char16_t *cmdline) {
uintptr_t shallocend = ROUNDUP(shadowend, FRAMESIZE);
uintptr_t shallocsize = shallocend - shallocaddr;
__imp_MapViewOfFileEx(
(_mmi.p[1].h =
__imp_CreateFileMappingW(-1, &kNtIsInheritable, kNtPageReadwrite,
shallocsize >> 32, shallocsize, NULL)),
(_mmi.p[1].h = __imp_CreateFileMappingW(
-1, 0, kNtPageReadwrite, shallocsize >> 32, shallocsize, NULL)),
kNtFileMapWrite, 0, 0, shallocsize, (void *)shallocaddr);
_mmi.p[1].x = shallocaddr >> 16;
_mmi.p[1].y = (shallocaddr >> 16) + ((shallocsize - 1) >> 16);

View file

@ -64,16 +64,16 @@ textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) {
if (writer != -1) __releasefd(writer);
return -1;
}
if ((hpipe = CreateNamedPipe(
pipename, kNtPipeAccessDuplex | kNtFileFlagOverlapped, mode, 1,
65536, 65536, 0, &kNtIsInheritable)) == -1) {
if ((hpipe = CreateNamedPipe(pipename,
kNtPipeAccessDuplex | kNtFileFlagOverlapped,
mode, 1, 65536, 65536, 0, 0)) == -1) {
__releasefd(writer);
__releasefd(reader);
return -1;
}
h1 = CreateFile(pipename, kNtGenericWrite | kNtGenericRead, 0,
&kNtIsInheritable, kNtOpenExisting, kNtFileFlagOverlapped, 0);
h1 = CreateFile(pipename, kNtGenericWrite | kNtGenericRead, 0, 0,
kNtOpenExisting, kNtFileFlagOverlapped, 0);
__fds_lock();

View file

@ -34,11 +34,13 @@
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/handlock.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/alloca.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/startupinfo.h"
@ -66,6 +68,14 @@ static void posix_spawn_cleanup3fds(int fds[3]) {
}
}
static void posix_spawn_inherit(int64_t hands[3], bool32 bInherit) {
for (int i = 0; i < 3; ++i) {
if (hands[i] != -1) {
SetHandleInformation(hands[i], kNtHandleFlagInherit, bInherit);
}
}
}
static const char *DescribePid(char buf[12], int err, int *pid) {
if (err) return "n/a";
if (!pid) return "NULL";
@ -176,9 +186,13 @@ static textwindows errno_t posix_spawn_windows_impl(
int rc, e = errno;
struct NtProcessInformation procinfo;
if (!envp) envp = environ;
__hand_rlock();
posix_spawn_inherit(stdio_handle, true);
rc = ntspawn(path, argv, envp, v, 0, 0, bInheritHandles, dwCreationFlags, 0,
&startinfo, &procinfo);
posix_spawn_inherit(stdio_handle, false);
posix_spawn_cleanup3fds(close_this_fd_later);
__hand_runlock();
if (rc == -1) {
int err = errno;
__releasefd(child);

View file

@ -24,6 +24,7 @@
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/handlock.internal.h"
#include "libc/intrin/leaky.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/memtrack.internal.h"
@ -64,11 +65,13 @@ void _pthread_onfork_prepare(void) {
_pthread_onfork(0);
pthread_spin_lock(&_pthread_lock);
__fds_lock();
__hand_lock();
__mmi_lock();
}
void _pthread_onfork_parent(void) {
__mmi_unlock();
__hand_unlock();
__fds_unlock();
pthread_spin_unlock(&_pthread_lock);
_pthread_onfork(1);
@ -87,6 +90,7 @@ void _pthread_onfork_child(void) {
atomic_store_explicit(&pt->cancelled, false, memory_order_relaxed);
// wipe core runtime locks
__hand_init();
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&__mmi_lock_obj, &attr);

View file

@ -252,7 +252,7 @@ void PosixSpawnWait(const char *prog) {
}
BENCH(posix_spawn, bench) {
long n = 128L * 1000 * 1000;
long n = 1L * 1000 * 1000;
memset(gc(malloc(n)), -1, n);
creat("tiny64", 0755);
write(3, kTinyLinuxExit, 128);