mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 09:18:31 +00:00
Make improvements
- Introduce path module to redbean - Fix glitch with linenoise printing extra line on eof - Introduce closefrom() and close_range() system calls - Make file descriptor closing more secure in pledge.com
This commit is contained in:
parent
439ad21b12
commit
1837dc2e85
31 changed files with 806 additions and 75 deletions
|
@ -69,6 +69,8 @@ int chown(const char *, uint32_t, uint32_t);
|
|||
int chroot(const char *);
|
||||
int clone(void *, void *, size_t, int, void *, int *, void *, int *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
int creat(const char *, uint32_t);
|
||||
int dup(int);
|
||||
int dup2(int, int);
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
/**
|
||||
* Closes file descriptor.
|
||||
*
|
||||
* This function may be used for file descriptors returned by socket,
|
||||
* accept, epoll_create, and zipos file descriptors too.
|
||||
* This function may be used for file descriptors returned by functions
|
||||
* like open, socket, accept, epoll_create, and landlock_create_ruleset.
|
||||
*
|
||||
* This function should never be called twice for the same file
|
||||
* descriptor, regardless of whether or not an error happened. However
|
||||
|
|
65
libc/calls/close_range.c
Normal file
65
libc/calls/close_range.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*-*- 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/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
* Closes inclusive range of file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (close_range(3, -1, 0) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This is supported on Linux 5.9+, FreeBSD, and OpenBSD. On FreeBSD,
|
||||
* `flags` must be zero. On OpenBSD, we call closefrom(int) so `last`
|
||||
* should be `-1` in order to get OpenBSD support, otherwise `ENOSYS`
|
||||
* will be returned. We also polyfill closefrom on FreeBSD since it's
|
||||
* available on older kernels.
|
||||
*
|
||||
* On Linux, the following flags are supported:
|
||||
*
|
||||
* - CLOSE_RANGE_UNSHARE
|
||||
* - CLOSE_RANGE_CLOEXEC
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
*/
|
||||
int close_range(unsigned int first, unsigned int last, unsigned int flags) {
|
||||
int rc, err;
|
||||
err = errno;
|
||||
if ((rc = sys_close_range(first, last, flags)) == -1) {
|
||||
if (errno == ENOSYS && first <= INT_MAX && last == UINT_MAX && !flags) {
|
||||
errno = err;
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
}
|
||||
STRACE("close_range(%d, %d, %#x) → %d% m", first, last, flags, rc);
|
||||
return rc;
|
||||
}
|
60
libc/calls/closefrom.c
Normal file
60
libc/calls/closefrom.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*-*- 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/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Closes extra file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (closefrom(3) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
* @note supported on Linux 5.9+, FreeBSD 8+, and OpenBSD
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
if (first >= 0) {
|
||||
err = errno;
|
||||
if ((rc = sys_close_range(first, -1, 0)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = err;
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
}
|
|
@ -28,6 +28,8 @@ i32 sys_arch_prctl(i32, i64) hidden;
|
|||
i32 sys_chdir(const char *) hidden;
|
||||
i32 sys_chroot(const char *) hidden;
|
||||
i32 sys_close(i32) hidden;
|
||||
i32 sys_close_range(u32, u32, u32) hidden;
|
||||
i32 sys_closefrom(i32) hidden;
|
||||
i32 sys_dup(i32) hidden;
|
||||
i32 sys_dup2(i32, i32) hidden;
|
||||
i32 sys_dup3(i32, i32, i32) hidden;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*
|
||||
* path │ dirname() │ basename()
|
||||
* ─────────────────────────────────
|
||||
* 0 │ . │ .
|
||||
* . │ . │ .
|
||||
* .. │ . │ ..
|
||||
* / │ / │ /
|
||||
|
@ -48,7 +49,7 @@ char *basename(char *path) {
|
|||
for (; i && _isdirsep(path[i]); i--) {
|
||||
path[i] = 0;
|
||||
}
|
||||
for (; i && !_isdirsep(path[i - 1]);) {
|
||||
while (i && !_isdirsep(path[i - 1])) {
|
||||
i--;
|
||||
}
|
||||
return path + i;
|
||||
|
|
|
@ -24,12 +24,18 @@
|
|||
/**
|
||||
* Joins paths, e.g.
|
||||
*
|
||||
* 0 + 0 → 0
|
||||
* "" + "" → ""
|
||||
* "a" + 0 → "a"
|
||||
* "a" + "" → "a/"
|
||||
* 0 + "b" → "b"
|
||||
* "" + "b" → "b"
|
||||
* "." + "b" → "./b"
|
||||
* "b" + "." → "b/."
|
||||
* "a" + "b" → "a/b"
|
||||
* "a/" + "b" → "a/b"
|
||||
* "a" + "b/" → "a/b/"
|
||||
* "a" + "/b" → "/b"
|
||||
* "." + "b" → "b"
|
||||
* "" + "b" → "b"
|
||||
*
|
||||
* @return joined path, which may be `buf`, `path`, or `other`, or null
|
||||
* if (1) `buf` didn't have enough space, or (2) both `path` and
|
||||
|
@ -39,14 +45,11 @@ char *_joinpaths(char *buf, size_t size, const char *path, const char *other) {
|
|||
size_t pathlen, otherlen;
|
||||
if (!other) return path;
|
||||
if (!path) return other;
|
||||
otherlen = strlen(other);
|
||||
if (!otherlen) {
|
||||
return (/*unconst*/ char *)path;
|
||||
}
|
||||
pathlen = strlen(path);
|
||||
if (!pathlen || (READ16LE(path) == READ16LE(".")) || *other == '/') {
|
||||
if (!pathlen || *other == '/') {
|
||||
return (/*unconst*/ char *)other;
|
||||
}
|
||||
otherlen = strlen(other);
|
||||
if (path[pathlen - 1] == '/') {
|
||||
if (pathlen + otherlen + 1 <= size) {
|
||||
memmove(buf, path, pathlen);
|
||||
|
|
|
@ -84,6 +84,7 @@ static const uint16_t kPledgeLinuxStdio[] = {
|
|||
__NR_linux_clock_getres, //
|
||||
__NR_linux_clock_gettime, //
|
||||
__NR_linux_clock_nanosleep, //
|
||||
__NR_linux_close_range, //
|
||||
__NR_linux_close, //
|
||||
__NR_linux_write, //
|
||||
__NR_linux_writev, //
|
||||
|
|
|
@ -296,6 +296,9 @@ static int sys_unveil_linux(const char *path, const char *permissions) {
|
|||
* possible to use opendir() and go fishing for paths which weren't
|
||||
* previously known.
|
||||
*
|
||||
* 5. Always specify at least one path. OpenBSD has unclear semantics
|
||||
* when `pledge(0,0)` is used without any previous calls.
|
||||
*
|
||||
* This system call is supported natively on OpenBSD and polyfilled on
|
||||
* Linux using the Landlock LSM[1].
|
||||
*
|
||||
|
@ -321,6 +324,7 @@ static int sys_unveil_linux(const char *path, const char *permissions) {
|
|||
* @raise EINVAL if one argument is set and the other is not
|
||||
* @raise EINVAL if an invalid character in `permissions` was found
|
||||
* @raise EPERM if unveil() is called after locking
|
||||
* @note on Linux this function requires Linux Kernel 5.13+
|
||||
* @see [1] https://docs.kernel.org/userspace-api/landlock.html
|
||||
*/
|
||||
int unveil(const char *path, const char *permissions) {
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall close_range,0xfffffffffffff1b4,globl
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall closefrom,0xfff11f1fdfffffff,globl
|
2
libc/sysv/calls/sys_close_range.s
Normal file
2
libc/sysv/calls/sys_close_range.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_close_range,0xffffff23fffff1b4,globl,hidden
|
2
libc/sysv/calls/sys_closefrom.s
Normal file
2
libc/sysv/calls/sys_closefrom.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_closefrom,0xfff11f1fdfffffff,globl,hidden
|
|
@ -586,6 +586,12 @@ syscon ss MINSIGSTKSZ 2048 32768 2048 12288 8192 2048 # overlayed
|
|||
syscon ss SS_ONSTACK 1 1 1 1 1 1 # unix consensus
|
||||
syscon ss SS_DISABLE 2 4 4 4 4 2 # bsd consensus
|
||||
|
||||
# close_range() values
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon close CLOSE_RANGE_UNSHARE 2 -1 -1 -1 -1 -1 #
|
||||
syscon close CLOSE_RANGE_CLOEXEC 4 -1 -1 -1 -1 -1 #
|
||||
|
||||
# clock_{gettime,settime} timers
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
|
|
16
libc/sysv/consts/close.h
Normal file
16
libc/sysv/consts/close.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOSE_H_
|
||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOSE_H_
|
||||
#include "libc/runtime/symbolic.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const long CLOSE_RANGE_UNSHARE;
|
||||
extern const long CLOSE_RANGE_CLOEXEC;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
#define CLOSE_RANGE_UNSHARE SYMBOLIC(CLOSE_RANGE_UNSHARE)
|
||||
#define CLOSE_RANGE_CLOEXEC SYMBOLIC(CLOSE_RANGE_CLOEXEC)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOSE_H_ */
|
|
@ -383,7 +383,7 @@ scall fsmount 0xfffffffffffff1b0 globl
|
|||
scall fspick 0xfffffffffffff1b1 globl
|
||||
scall pidfd_open 0xfffffffffffff1b2 globl
|
||||
scall clone3 0xfffffffffffff1b3 globl
|
||||
scall close_range 0xfffffffffffff1b4 globl
|
||||
scall sys_close_range 0xffffff23fffff1b4 globl hidden # linux 5.9
|
||||
scall sys_openat2 0xfffffffffffff1b5 globl hidden # Linux 5.6
|
||||
scall pidfd_getfd 0xfffffffffffff1b6 globl
|
||||
scall sys_faccessat2 0xfffffffffffff1b7 globl hidden
|
||||
|
@ -463,7 +463,7 @@ scall chflagsat 0xfff06b21cfffffff globl
|
|||
scall profil 0x02c02c02cfffffff globl
|
||||
scall fhstatfs 0xfff04122efffffff globl
|
||||
scall utrace 0x1320d114ffffffff globl
|
||||
scall closefrom 0xfff11f1fdfffffff globl
|
||||
scall sys_closefrom 0xfff11f1fdfffffff globl hidden
|
||||
#───────────────────────────XNU──────────────────────────────
|
||||
scall __pthread_markcancel 0xfffffffff214cfff globl
|
||||
scall __pthread_kill 0xfffffffff2148fff globl
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue