Fix bugs and add security features to redbean

- Fix a regression with the previous change that broke redbean
- Add chroot(), resource limit, seccomp, and other stuff to redbean
- Write lots and lots of documentation
- Iron out more system call issues
This commit is contained in:
Justine Tunney 2022-04-18 00:01:26 -07:00
parent f1dfa4bdfa
commit 7166679620
182 changed files with 1855 additions and 918 deletions

View file

@ -155,7 +155,7 @@ int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int);
int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_madvise(void *, uint64_t, int);
int prctl();
int prctl(int, ...);
int raise(int);
int reboot(int);
int remove(const char *);
@ -232,6 +232,7 @@ uint32_t umask(uint32_t);
void rewinddir(DIR *);
void sync(void);
int getloadavg(double *, int);
int seccomp(unsigned, unsigned, void *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » formatting

View file

@ -83,6 +83,9 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \
-O3
# TODO(jart): make va_arg optimize well in default mode
o//libc/calls/open.o \
o//libc/calls/openat.o \
o//libc/calls/prctl.o \
o//libc/calls/ioctl.o \
o//libc/calls/ioctl_default.o \
o//libc/calls/ioctl_fioclex-nt.o \

View file

@ -76,5 +76,5 @@ textwindows int sys_chdir_nt(const char *path) {
}
}
}
return -1;
return __fix_enotdir(-1, path16);
}

View file

@ -32,7 +32,7 @@
*/
int chdir(const char *path) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_chdir(path);

33
libc/calls/chroot.c Normal file
View file

@ -0,0 +1,33 @@
/*-*- 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 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
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/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Changes root directory.
*
* @raise ENOSYS on Windows
*/
int chroot(const char *path) {
int rc;
rc = sys_chroot(path);
STRACE("chroot(%s) → %d% m", path, rc);
return rc;
}

View file

@ -22,7 +22,6 @@
#include "libc/intrin/describeflags.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/str/str.h"
/**
@ -32,6 +31,9 @@
* support Windows NT and Address Sanitizer. That memory tracking can be
* bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle().
*
* @asyncsignalsafe
* @threadsafe
*/
struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) {

View file

@ -24,5 +24,5 @@
int sys_faccessat_nt(int dirfd, const char *path, int mode, uint32_t flags) {
char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
return ntaccesscheck(path16, mode);
return __fix_enotdir(ntaccesscheck(path16, mode), path16);
}

63
libc/calls/fixenotdir.c Normal file
View file

@ -0,0 +1,63 @@
/*-*- 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 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
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/calls/internal.h"
#include "libc/errno.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
static textwindows bool SubpathExistsThatsNotDirectory(char16_t *path) {
int e;
char16_t *p;
uint32_t attrs;
e = errno;
while ((p = strrchr16(path, '\\'))) {
*p = u'\0';
if ((attrs = GetFileAttributes(path)) != -1u) {
if (attrs & kNtFileAttributeDirectory) {
return false;
} else {
return true;
}
} else {
errno = e;
}
}
return false;
}
// WIN32 doesn't distinguish between ENOTDIR and ENOENT. UNIX strictly
// requires that a directory component *exists* but is not a directory
// whereas WIN32 will return ENOTDIR if a dir label simply isn't found
//
// - ENOTDIR: A component used as a directory in pathname is not, in
// fact, a directory. -or- pathname is relative and dirfd is a file
// descriptor referring to a file other than a directory.
//
// - ENOENT: A directory component in pathname does not exist or is a
// dangling symbolic link.
//
textwindows int64_t __fix_enotdir(int64_t rc, char16_t *path) {
if (rc == -1 && errno == kNtErrorPathNotFound) {
if (!SubpathExistsThatsNotDirectory(path)) {
errno = kNtErrorFileNotFound;
}
}
return rc;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/errfuns.h"
/**
@ -36,10 +37,16 @@ int getrlimit(int resource, struct rlimit *rlim) {
char buf[64];
if (resource == 127) {
rc = einval();
} else if (IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim))) {
} else if (!rlim || (IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim)))) {
rc = efault();
} else {
} else if (!IsWindows()) {
rc = sys_getrlimit(resource, rlim);
} else if (resource == RLIMIT_AS) {
rlim->rlim_cur = __virtualmax;
rlim->rlim_max = __virtualmax;
rc = 0;
} else {
rc = einval();
}
STRACE("getrlimit(%s, [%s]) → %d% m", __strace_rlimit_name(resource),
__strace_rlimit(buf, sizeof(buf), rc, rlim), rc);

View file

@ -5,6 +5,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction-xnu.internal.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
@ -133,6 +134,7 @@ i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden;
i32 sys_chdir(const char *) hidden;
i32 sys_chroot(const char *) hidden;
i32 sys_clock_gettime(i32, struct timespec *) hidden;
i32 sys_close(i32) hidden;
i32 sys_dup(i32) hidden;
@ -310,6 +312,7 @@ int sys_sync_nt(void) hidden;
int sys_sysinfo_nt(struct sysinfo *) hidden;
int sys_truncate_nt(const char *, u64) hidden;
int sys_unlinkat_nt(int, const char *, int) hidden;
int sys_setrlimit_nt(int, const struct rlimit *) hidden;
int sys_utimensat_nt(int, const char *, const struct timespec *, int) hidden;
int sys_utimes_nt(const char *, const struct timeval[2]) hidden;
ssize_t sys_open_nt(int, const char *, u32, i32) dontdiscard hidden;
@ -322,6 +325,7 @@ int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden;
cosmopolitan § syscalls » windows nt » support
*/
int64_t __fix_enotdir(int64_t, char16_t *) hidden;
bool _check_interrupts(bool, struct Fd *) hidden;
void _check_sigchld(void) hidden;
void _check_sigalrm(void) hidden;

10
libc/calls/issandboxed.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_ISSANDBOXED_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_ISSANDBOXED_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool __issandboxed;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_ISSANDBOXED_INTERNAL_H_ */

View file

@ -17,50 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/str/str.h"
static textwindows bool SubpathExistsThatsNotDirectory(char16_t *path) {
int e;
char16_t *p;
uint32_t attrs;
e = errno;
while ((p = strrchr16(path, '\\'))) {
*p = u'\0';
if ((attrs = GetFileAttributes(path)) != -1u) {
if (attrs & kNtFileAttributeDirectory) {
return false;
} else {
return true;
}
} else {
errno = e;
}
}
return false;
}
textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) {
int e;
char16_t *p, path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
if (CreateDirectory(path16, 0)) return 0;
// WIN32 doesn't distinguish between ENOTDIR and ENOENT
//
// - ENOTDIR: A component used as a directory in pathname is not, in
// fact, a directory. -or- pathname is relative and dirfd is a file
// descriptor referring to a file other than a directory.
//
// - ENOENT: A directory component in pathname does not exist or is a
// dangling symbolic link.
if (errno == ENOTDIR) {
if (!SubpathExistsThatsNotDirectory(path16)) {
errno = ENOENT;
}
}
return -1;
return __fix_enotdir(-1, path16);
}

View file

@ -19,8 +19,16 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
/**
* Unmaps memory directly with system.
*
* This function bypasses memtrack. Therefore it won't work on Windows,
* but it works on everything else including bare metal.
*
* @asyncsignalsafe
* @threadsafe
*/
int sys_munmap(void *p, size_t n) {
int rc;
if (!IsMetal()) {

View file

@ -42,7 +42,9 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
uint32_t perm, share, disp, attr;
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
if (GetNtOpenFlags(flags, mode, &perm, &share, &disp, &attr) == -1) return -1;
return CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, 0);
return __fix_enotdir(
CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, 0),
path16);
}
static textwindows ssize_t sys_open_nt_console(int dirfd,

View file

@ -87,11 +87,13 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
if (rc == -1 && errno == EFAULT) {
STRACE("poll(%p, %'lu, %'d) → %d% lm", fds, nfds, timeout_ms, rc);
} else {
char flagbuf[2][64];
kprintf(STRACE_PROLOGUE "poll({");
for (i = 0; i < MIN(5, nfds); ++i) {
kprintf("%s{%d,%s,%s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(fds[i].events),
DescribePollFlags(fds[i].revents));
kprintf(
"%s{%d, %s, %s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(flagbuf[0], sizeof(flagbuf[0]), fds[i].events),
DescribePollFlags(flagbuf[1], sizeof(flagbuf[1]), fds[i].revents));
}
kprintf("%s}, %'zu, %'d) → %d% lm%n", i == 5 ? "..." : "", nfds,
timeout_ms, rc);

52
libc/calls/prctl.c Normal file
View file

@ -0,0 +1,52 @@
/*-*- 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 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
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/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/errno.h"
#include "libc/sysv/errfuns.h"
/**
* Tunes process on Linux.
*
* @raise ENOSYS on non-Linux.
*/
int prctl(int operation, ...) {
int rc;
va_list va;
intptr_t a, b;
register intptr_t c asm("r10");
register intptr_t d asm("r8");
va_start(va, operation);
a = va_arg(va, intptr_t);
b = va_arg(va, intptr_t);
c = va_arg(va, intptr_t);
d = va_arg(va, intptr_t);
va_end(va);
if (IsLinux()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(157), "D"(operation), "S"(a), "d"(b), "r"(c), "r"(d)
: "rcx", "r11", "memory");
if (rc > -4096u) errno = -rc, rc = -1;
} else {
rc = enosys();
}
STRACE("seccomp(%d, %p, %p, %p, %p) → %d% m", operation, a, b, c, d, rc);
return rc;
}

View file

@ -56,7 +56,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
rc = ebadf();
}
assert(rc == -1 || (size_t)rc <= size);
STRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
return rc;
}

View file

@ -58,7 +58,7 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
assert(wrote <= size);
}
}
STRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, offset, rc);
DATATRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
return rc;
}

View file

@ -62,7 +62,7 @@ ssize_t read(int fd, void *buf, size_t size) {
} else {
rc = einval();
}
STRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)), buf,
rc > 40 ? "..." : "", size, rc);
DATATRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -40,7 +41,9 @@
* @restartable
*/
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc;
int i;
ssize_t rc, rem;
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
@ -63,6 +66,27 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
} else {
rc = einval();
}
STRACE("readv(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("readv(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
} else {
rem = rc != -1 ? rc : 0;
kprintf(STRACE_PROLOGUE "readv(%d, [{", fd);
for (i = 0; i < MIN(5, iovlen); ++i) {
kprintf("%s{%#.*hhs%s, %'zu}", i ? ", " : "",
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))), iov[i].iov_base,
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))) < iov[i].iov_len
? "..."
: "",
iov[i].iov_len);
rem -= iov[i].iov_len;
}
kprintf("%s}], %d) → %'ld% m%n", iovlen > 5 ? "..." : "", iovlen, rc);
}
}
#endif
return rc;
}

69
libc/calls/seccomp.c Normal file
View file

@ -0,0 +1,69 @@
/*-*- 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 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
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/calls/calls.h"
#include "libc/calls/issandboxed.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/seccomp.h"
#include "libc/sysv/errfuns.h"
/**
* Tunes Linux security policy.
*
* This system call was first introduced in Linux 3.17. We polyfill
* automatically features like SECCOMP_SET_MODE_STRICT, for kernels
* dating back to 2.6.23, whenever possible.
*
* @raise ENOSYS on non-Linux.
*/
int seccomp(unsigned operation, unsigned flags, void *args) {
int rc;
if (IsLinux()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(317), "D"(operation), "S"(flags), "d"(args)
: "rcx", "r11", "memory");
if (rc == -ENOSYS) {
if (operation == SECCOMP_SET_MODE_STRICT) {
asm volatile("syscall"
: "=a"(rc)
: "0"(157), "D"(PR_SET_SECCOMP), "S"(SECCOMP_MODE_STRICT)
: "rcx", "r11", "memory");
} else if (operation == SECCOMP_SET_MODE_FILTER && !flags) {
asm volatile("syscall"
: "=a"(rc)
: "0"(157), "D"(PR_SET_SECCOMP), "S"(SECCOMP_MODE_FILTER),
"d"(args)
: "rcx", "r11", "memory");
}
}
if (rc > -4096u) {
errno = -rc;
rc = -1;
}
} else {
rc = enosys();
}
STRACE("seccomp(%s, %#x, %p) → %d% m",
DescribeSeccompOperationFlags(operation), flags, args, rc);
return rc;
}

View file

@ -16,17 +16,39 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/errfuns.h"
/**
* Sets resource limit for current process.
*
* @param resource can be RLIMIT_{CPU,FSIZE,DATA,STACK,CORE,RSS,etc.}
* The following resources are recommended:
*
* - `RLIMIT_AS` limits the size of the virtual address space. This will
* work on all platforms. It's emulated on XNU and Windows which means
* it won't propagate across execve() currently.
*
* - `RLIMIT_CPU` causes `SIGXCPU` to be sent to the process when the
* soft limit on CPU time is exceeded, and the process is destroyed
* when the hard limit is exceeded. It works everywhere but Windows
* where it should be possible to poll getrusage() with setitimer()
*
* - `RLIMIT_FSIZE` causes `SIGXFSZ` to sent to the process when the
* soft limit on file size is exceeded and the process is destroyed
* when the hard limit is exceeded. It works everywhere but Windows
*
* - `RLIMIT_NPROC` limits the number of simultaneous processes and it
* should work on all platforms except Windows.
*
* - `RLIMIT_NOFILE` limits the number of open file descriptors and it
* should work on all platforms except Windows (TODO)
*
* @param rlim specifies new resource limit
* @return 0 on success or -1 w/ errno
* @see libc/sysv/consts.sh
@ -37,10 +59,19 @@ int setrlimit(int resource, const struct rlimit *rlim) {
char buf[64];
if (resource == 127) {
rc = einval();
} else if (IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim))) {
} else if (!rlim || (IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim)))) {
rc = efault();
} else {
} else if (!IsWindows()) {
rc = sys_setrlimit(resource, rlim);
if (IsXnu() && !rc && resource == RLIMIT_AS) {
// TODO(jart): What's up with XNU and NetBSD?
__virtualmax = rlim->rlim_cur;
}
} else if (resource == RLIMIT_AS) {
__virtualmax = rlim->rlim_cur;
rc = 0;
} else {
rc = einval();
}
STRACE("setrlimit(%s, %s) → %d% m", __strace_rlimit_name(resource),
__strace_rlimit(buf, sizeof(buf), 0, rlim), rc);

View file

@ -24,6 +24,10 @@ void __stat2cosmo(struct stat *restrict st, const union metastat *ms) {
if (st) {
if (IsLinux()) {
st->st_birthtim = st->st_ctim;
if (st->st_atim.tv_sec < st->st_ctim.tv_sec)
st->st_birthtim = st->st_atim;
if (st->st_mtim.tv_sec < st->st_ctim.tv_sec)
st->st_birthtim = st->st_mtim;
} else if (IsXnu()) {
st->st_dev = ms->xnu.st_dev;
st->st_ino = ms->xnu.st_ino;

View file

@ -7,6 +7,7 @@
#define _NT_RLIMIT_PWSS_MB 1000 /* nocommit */
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
@ -25,6 +26,12 @@ COSMOPOLITAN_C_START_
#define STRACE(FMT, ...) (void)0
#endif
#if defined(SYSDEBUG) && _DATATRACE
#define DATATRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
#else
#define DATATRACE(FMT, ...) (void)0
#endif
#if defined(SYSDEBUG) && _POLLTRACE
#define POLLTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
#else

View file

@ -0,0 +1,54 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SECCOMP_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SECCOMP_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct seccomp_data {
int32_t nr;
uint32_t arch;
uint64_t instruction_pointer;
uint64_t args[6];
};
struct seccomp_notif_sizes {
uint16_t seccomp_notif;
uint16_t seccomp_notif_resp;
uint16_t seccomp_data;
};
struct seccomp_notif {
uint64_t id;
uint32_t pid;
uint32_t flags;
struct seccomp_data data;
};
struct seccomp_notif_resp {
uint64_t id;
int64_t val;
int32_t error;
uint32_t flags;
};
struct seccomp_notif_addfd {
uint64_t id;
uint32_t flags;
uint32_t srcfd;
uint32_t newfd;
uint32_t newfd_flags;
};
#define SECCOMP_IOC_MAGIC '!'
#define SECCOMP_IO(nr) _IO(SECCOMP_IOC_MAGIC, nr)
#define SECCOMP_IOR(nr, type) _IOR(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOW(nr, type) _IOW(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOWR(nr, type) _IOWR(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOCTL_NOTIF_RECV SECCOMP_IOWR(0, struct seccomp_notif)
#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, struct seccomp_notif_resp)
#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOW(2, __u64)
#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, struct seccomp_notif_addfd)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SECCOMP_H_ */

28
libc/calls/virtualmax.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 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
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/calls/calls.h"
/**
* Maximum amount of virtual memory in bytes.
*
* mmap() will return ENOMEM once this is reached.
*
* By default no limit is imposed.
*/
size_t __virtualmax;

View file

@ -51,6 +51,8 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
__sig_raise(SIGPIPE, SI_KERNEL);
return epipe();
}
// kNtErrorInvalidHandle → EBADF (consts.sh)
// kNtErrorNotEnoughQuota → EDQUOT (consts.sh; SetProcessWorkingSetSize)
return __winerr();
}

View file

@ -59,7 +59,7 @@ ssize_t write(int fd, const void *buf, size_t size) {
} else {
rc = einval();
}
STRACE("write(%d, %#.*hhs%s, %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)), buf,
rc > 40 ? "..." : "", size, rc);
DATATRACE("write(%d, %#.*hhs%s, %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, rc);
return rc;
}

View file

@ -20,7 +20,9 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -44,7 +46,9 @@
* @restartable
*/
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc;
int i;
ssize_t rc, rem;
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
@ -67,6 +71,27 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
} else {
rc = einval();
}
STRACE("writev(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("writev(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
} else {
rem = rc != -1 ? rc : 0;
kprintf(STRACE_PROLOGUE "writev(%d, {", fd);
for (i = 0; i < MIN(5, iovlen); ++i) {
kprintf("%s{%#.*hhs%s, %'zu}", i ? ", " : "",
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))), iov[i].iov_base,
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))) < iov[i].iov_len
? "..."
: "",
iov[i].iov_len);
rem -= iov[i].iov_len;
}
kprintf("%s}, %d) → %'ld% m%n", iovlen > 5 ? "..." : "", iovlen, rc);
}
}
#endif
return rc;
}