Improve pledge() and unveil()

The pledge.com command now supports the new [WIP] unveil() support. For
example, to strongly sandbox our command for listing directories.

    o//tool/build/assimilate.com o//examples/ls.com
    pledge.com -v /etc -p 'stdio rpath' o//examples/ls.com /etc

This file system sandboxing is going to be perfect for us, because APE
binaries are self-contained static executables that really don't use the
filesystem that much. On the other hand, with non-static executables,
sandboxing is going to be more difficult. For example, here's how to
sandbox the `ls` command on the latest Alpine:

    pledge.com -v rx:/lib -v /usr/lib -v /etc -p 'stdio rpath exec' ls /etc

This change fixes the `execpromises` API with pledge().

This change also adds unix.unveil() to redbean.

Fixes #494
This commit is contained in:
Justine Tunney 2022-07-18 07:23:15 -07:00
parent b1d9d11be1
commit e81edf7b04
19 changed files with 535 additions and 150 deletions

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
@ -24,10 +25,13 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
int sys_pledge_linux(unsigned long);
/**
* Replaces current process with program.
*
@ -66,7 +70,13 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
}
#endif
if (!IsWindows()) {
rc = sys_execve(prog, argv, envp);
rc = 0;
if (IsLinux() && __execpromises && weaken(sys_pledge_linux)) {
rc = weaken(sys_pledge_linux)(__execpromises);
}
if (!rc) {
rc = sys_execve(prog, argv, envp);
}
} else {
rc = sys_execve_nt(prog, argv, envp);
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
@ -36,18 +37,27 @@
* @param path is a filename or directory
* @param mode can be R_OK, W_OK, X_OK, F_OK
* @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
* @note on Linux flags is only supported on Linux 5.8+
* @return 0 if ok, or -1 and sets errno
* @asyncsignalsafe
*/
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
int rc;
int e, rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
rc = efault();
} else if (weaken(__zipos_notat) &&
weaken(__zipos_notat)(dirfd, path) == -1) {
rc = -1; /* TODO(jart): implement me */
} else if (!IsWindows()) {
rc = sys_faccessat(dirfd, path, mode, flags);
e = errno;
if (!flags) goto NoFlags;
if ((rc = sys_faccessat2(dirfd, path, mode, flags)) == -1) {
if (errno == ENOSYS) {
errno = e;
NoFlags:
rc = sys_faccessat(dirfd, path, mode, flags);
}
}
} else {
rc = sys_faccessat_nt(dirfd, path, mode, flags);
}

View file

@ -33,6 +33,7 @@ i32 sys_dup2(i32, i32) hidden;
i32 sys_dup3(i32, i32, i32) hidden;
i32 sys_execve(const char *, char *const[], char *const[]) hidden;
i32 sys_faccessat(i32, const char *, i32, u32) hidden;
i32 sys_faccessat2(i32, const char *, i32, u32) hidden;
i32 sys_fadvise(i32, i64, i64, i32) hidden;
i32 sys_fchdir(i32) hidden;
i32 sys_fchmod(i32, u32) hidden;
@ -95,6 +96,7 @@ i32 sys_tkill(i32, i32, void *) hidden;
i32 sys_truncate(const char *, u64, u64) hidden;
i32 sys_uname(char *) hidden;
i32 sys_unlinkat(i32, const char *, i32) hidden;
i32 sys_unveil(const char *, const char *) hidden;
i64 sys_copy_file_range(i32, long *, i32, long *, u64, u32) hidden;
i64 sys_getrandom(void *, u64, u32) hidden;
i64 sys_pread(i32, void *, u64, i64, i64) hidden;
@ -111,7 +113,6 @@ u32 sys_geteuid(void) hidden;
u32 sys_getgid(void) hidden;
u32 sys_getuid(void) hidden;
u32 sys_umask(u32) hidden;
i32 sys_unveil(const char *, const char *) hidden;
void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
void *sys_mremap(void *, u64, u64, i32, void *) hidden;
void sys_exit(int) hidden;

View file

@ -19,3 +19,4 @@
#include "libc/intrin/promises.internal.h"
unsigned long __promises;
unsigned long __execpromises;

View file

@ -1,33 +1,33 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_PROMISES_H_
#define COSMOPOLITAN_LIBC_INTRIN_PROMISES_H_
#define PROMISE_DEFAULT 0
#define PROMISE_STDIO 1
#define PROMISE_RPATH 2
#define PROMISE_WPATH 3
#define PROMISE_CPATH 4
#define PROMISE_DPATH 5
#define PROMISE_FLOCK 6
#define PROMISE_FATTR 7
#define PROMISE_INET 8
#define PROMISE_UNIX 9
#define PROMISE_DNS 10
#define PROMISE_TTY 11
#define PROMISE_RECVFD 12
#define PROMISE_PROC 13
#define PROMISE_THREAD 14
#define PROMISE_EXEC 15
#define PROMISE_EXECNATIVE 16
#define PROMISE_ID 17
#define PROMISE_UNVEIL 18
#define PROMISE_MAX 18
#define PROMISE_STDIO 0
#define PROMISE_RPATH 1
#define PROMISE_WPATH 2
#define PROMISE_CPATH 3
#define PROMISE_DPATH 4
#define PROMISE_FLOCK 5
#define PROMISE_FATTR 6
#define PROMISE_INET 7
#define PROMISE_UNIX 8
#define PROMISE_DNS 9
#define PROMISE_TTY 10
#define PROMISE_RECVFD 11
#define PROMISE_PROC 12
#define PROMISE_THREAD 13
#define PROMISE_EXEC 14
#define PROMISE_EXECNATIVE 15
#define PROMISE_ID 16
#define PROMISE_UNVEIL 17
#define PROMISE_SENDFD 18
#define PLEDGED(x) (~__promises & (1L << PROMISE_##x))
#define PLEDGED(x) ((~__promises >> PROMISE_##x) & 1)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
hidden extern unsigned long __promises;
hidden extern unsigned long __execpromises;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -25,7 +25,6 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
@ -157,6 +156,7 @@ static const uint16_t kPledgeLinuxRpath[] = {
__NR_linux_fstatat, //
__NR_linux_access, //
__NR_linux_faccessat, //
__NR_linux_faccessat2, //
__NR_linux_readlink, //
__NR_linux_readlinkat, //
__NR_linux_statfs, //
@ -173,6 +173,7 @@ static const uint16_t kPledgeLinuxWpath[] = {
__NR_linux_fstatat, //
__NR_linux_access, //
__NR_linux_faccessat, //
__NR_linux_faccessat2, //
__NR_linux_readlinkat, //
__NR_linux_chmod, //
__NR_linux_fchmod, //
@ -254,6 +255,10 @@ static const uint16_t kPledgeLinuxRecvfd[] = {
__NR_linux_recvmsg, //
};
static const uint16_t kPledgeLinuxSendfd[] = {
__NR_linux_sendmsg, //
};
static const uint16_t kPledgeLinuxProc[] = {
__NR_linux_fork, //
__NR_linux_vfork, //
@ -268,8 +273,10 @@ static const uint16_t kPledgeLinuxProc[] = {
};
static const uint16_t kPledgeLinuxThread[] = {
__NR_linux_clone, //
__NR_linux_futex, //
__NR_linux_clone, //
__NR_linux_futex, //
__NR_linux_set_robust_list, //
__NR_linux_get_robust_list, //
};
static const uint16_t kPledgeLinuxId[] = {
@ -313,7 +320,6 @@ static const struct Pledges {
const uint16_t *syscalls;
const size_t len;
} kPledgeLinux[] = {
[PROMISE_DEFAULT] = {"default", PLEDGE(kPledgeLinuxDefault)}, //
[PROMISE_STDIO] = {"stdio", PLEDGE(kPledgeLinuxStdio)}, //
[PROMISE_RPATH] = {"rpath", PLEDGE(kPledgeLinuxRpath)}, //
[PROMISE_WPATH] = {"wpath", PLEDGE(kPledgeLinuxWpath)}, //
@ -326,13 +332,13 @@ static const struct Pledges {
[PROMISE_DNS] = {"dns", PLEDGE(kPledgeLinuxDns)}, //
[PROMISE_TTY] = {"tty", PLEDGE(kPledgeLinuxTty)}, //
[PROMISE_RECVFD] = {"recvfd", PLEDGE(kPledgeLinuxRecvfd)}, //
[PROMISE_SENDFD] = {"sendfd", PLEDGE(kPledgeLinuxSendfd)}, //
[PROMISE_PROC] = {"proc", PLEDGE(kPledgeLinuxProc)}, //
[PROMISE_THREAD] = {"thread", PLEDGE(kPledgeLinuxThread)}, //
[PROMISE_EXEC] = {"exec", PLEDGE(kPledgeLinuxExec)}, //
[PROMISE_EXECNATIVE] = {"execnative", PLEDGE(kPledgeLinuxExec2)}, //
[PROMISE_ID] = {"id", PLEDGE(kPledgeLinuxId)}, //
[PROMISE_UNVEIL] = {"unveil", PLEDGE(kPledgeLinuxUnveil)}, //
[PROMISE_MAX + 1] = {0}, //
};
static const struct sock_filter kFilterStart[] = {
@ -342,6 +348,13 @@ static const struct sock_filter kFilterStart[] = {
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
// each filter assumes ordinal is already loaded into accumulator
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
// Forbid some system calls with ENOSYS (rather than EPERM)
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_openat2, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (38 & SECCOMP_RET_DATA)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_clone3, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (38 & SECCOMP_RET_DATA)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_statx, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (38 & SECCOMP_RET_DATA)),
};
static const struct sock_filter kFilterEnd[] = {
@ -957,8 +970,8 @@ static bool AllowFchmodat(struct Filter *f) {
return AppendFilter(f, PLEDGE(fragment));
}
static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len, bool needmapexec,
bool needmorphing) {
static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len,
bool needmapexec, bool needmorphing) {
int i;
for (i = 0; i < len; ++i) {
switch (p[i]) {
@ -1045,83 +1058,100 @@ static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len, bool n
return true;
}
static int FindPromise(const struct Pledges *p, const char *name, size_t *len) {
int i;
for (i = 0; p[i].name; ++i) {
if (!strcasecmp(name, p[i].name)) {
*len = p[i].len;
return i;
}
}
return -1;
}
static int sys_pledge_linux(const char *promises, const char *execpromises) {
bool ok;
int rc = -1;
size_t plen;
int promise;
int sys_pledge_linux(unsigned long ipromises) {
bool ok = true;
int i, rc = -1;
bool needmapexec;
bool needexecnative;
bool needmorphing;
bool needexecnative;
struct Filter f = {0};
const uint16_t *pledge;
unsigned long ipromises = -1;
char *s, *tok, *state, *start;
if (execpromises) return einval();
needmapexec = strstr(promises, "exec");
needmorphing = strstr(promises, "thread");
needexecnative = strstr(promises, "execnative");
if ((start = s = strdup(promises)) && AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
ipromises = ~ipromises;
needmapexec = (ipromises >> PROMISE_EXEC) & 1;
needmorphing = (ipromises >> PROMISE_THREAD) & 1;
needexecnative = (ipromises >> PROMISE_EXECNATIVE) & 1;
if (AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
(needmapexec || needexecnative || AppendOriginVerification(&f)) &&
AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault), needmapexec,
needmorphing)) {
for (ok = true; (tok = strtok_r(start, " \t\r\n", &state)); start = 0) {
if ((promise = FindPromise(kPledgeLinux, tok, &plen)) != -1) {
pledge = kPledgeLinux[promise].syscalls;
ipromises &= ~(1ULL << promise);
} else {
ok = false;
rc = einval();
break;
}
if (!AppendPledge(&f, pledge, plen, needmapexec, needmorphing)) {
ok = false;
break;
AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault),
needmapexec, needmorphing)) {
for (i = 0; i < ARRAYLEN(kPledgeLinux); ++i) {
if ((ipromises & (1ul << i)) && kPledgeLinux[i].name) {
ipromises &= ~(1ul << i);
if (!AppendPledge(&f, kPledgeLinux[i].syscalls, kPledgeLinux[i].len,
needmapexec, needmorphing)) {
ok = false;
rc = einval();
break;
}
}
}
if (ipromises) {
ok = false;
rc = einval();
}
if (ok && AppendFilter(&f, kFilterEnd, ARRAYLEN(kFilterEnd)) &&
(rc = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) != -1) {
struct sock_fprog sandbox = {.len = f.n, .filter = f.p};
rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sandbox);
}
if (!rc) {
__promises = ipromises;
}
}
free(f.p);
free(s);
return rc;
}
static void SetPromises(const char *promises) {
int promise;
size_t plen;
char *tok, *state, *start;
unsigned long ipromises = -1;
while ((tok = strtok_r(start, " \t\r\n", &state))) {
if ((promise = FindPromise(kPledgeLinux, tok, &plen)) != -1) {
ipromises &= ~(1ULL << promise);
static int FindPromise(const char *name) {
int i;
for (i = 0; i < ARRAYLEN(kPledgeLinux); ++i) {
if (!strcasecmp(name, kPledgeLinux[i].name)) {
return i;
}
start = 0;
}
__promises = ipromises;
STRACE("unknown promise %s", name);
return -1;
}
static int ParsePromises(const char *promises, unsigned long *out) {
int rc = 0;
int promise;
unsigned long ipromises;
char *tok, *state, *start, *freeme;
if (promises) {
ipromises = -1;
freeme = start = strdup(promises);
while ((tok = strtok_r(start, " \t\r\n", &state))) {
if ((promise = FindPromise(tok)) != -1) {
ipromises &= ~(1ULL << promise);
} else {
rc = einval();
break;
}
start = 0;
}
free(freeme);
} else {
ipromises = 0;
}
if (!rc) {
*out = ipromises;
}
return rc;
}
static void FixupOpenbsdPromises(char *p) {
if (!p) return;
if ((p = strstr(p, "execnative"))) {
p[4] = ' ';
p[5] = ' ';
p[6] = ' ';
p[7] = ' ';
p[8] = ' ';
p[9] = ' ';
}
}
/**
* Restricts system operations, e.g.
*
* pledge("stdio tty", 0);
* pledge("stdio rfile tty", 0);
*
* Pledging causes most system calls to become unavailable. Your system
* call policy is enforced by the kernel, which means it can propagate
@ -1185,12 +1215,13 @@ static void SetPromises(const char *promises) {
* fcntl(F_GETFL), fcntl(F_SETFL).
*
* - "rpath" (read-only path ops) allows chdir, getcwd, open(O_RDONLY),
* openat(O_RDONLY), stat, fstat, lstat, fstatat, access, faccessat,
* readlink, readlinkat, statfs, fstatfs.
* openat(O_RDONLY), stat, fstat, lstat, fstatat, access,
* faccessat,faccessat2, readlink, readlinkat, statfs, fstatfs.
*
* - "wpath" (write path ops) allows getcwd, open(O_WRONLY),
* openat(O_WRONLY), stat, fstat, lstat, fstatat, access, faccessat,
* readlink, readlinkat, chmod, fchmod, fchmodat.
* openat(O_WRONLY), stat, fstat, lstat, fstatat, access,
* faccessat,faccessat2, readlink, readlinkat, chmod, fchmod,
* fchmodat.
*
* - "cpath" (create path ops) allows open(O_CREAT), openat(O_CREAT),
* rename, renameat, renameat2, link, linkat, symlink, symlinkat,
@ -1204,7 +1235,9 @@ static void SetPromises(const char *promises) {
* - "tty" allows ioctl(TIOCGWINSZ), ioctl(TCGETS), ioctl(TCSETS),
* ioctl(TCSETSW), ioctl(TCSETSF).
*
* - "recvfd" allows recvmsg(SCM_RIGHTS).
* - "recvfd" allows recvmsg in general (for SCM_RIGHTS).
*
* - "recvfd" allows sendmsg in general (for SCM_RIGHTS).
*
* - "fattr" allows chmod, fchmod, fchmodat, utime, utimes, futimens,
* utimensat.
@ -1236,24 +1269,70 @@ static void SetPromises(const char *promises) {
* native executables; you won't be able to run APE binaries. mmap()
* and mprotect() are still prevented from creating executable memory.
* System call origin verification can't be enabled. If you always
* assimilate your APE binaries, then this should be preferred.
* assimilate your APE binaries, then this should be preferred. On
* OpenBSD this will be rewritten to be "exec".
*
* - "unveil" allows unveil() to be called, as well as the underlying
* landlock_create_ruleset, landlock_add_rule, landlock_restrict_self
* calls on Linux.
*
* `execpromises` only matters if "exec" or "execnative" are specified
* in `promises`. In that case, this specifies the promises that'll
* apply once execve() happens. If this is NULL then the default is
* used, which is unrestricted. OpenBSD allows child processes to escape
* the sandbox (so a pledged OpenSSH server process can do things like
* spawn a root shell). Linux however requires monotonically decreasing
* privileges. This function will will perform some validation on Linux
* to make sure that `execpromises` is a subset of `promises`. Your libc
* wrapper for execve() will then apply its SECCOMP BPF filter later.
* Since Linux has to do this before calling sys_execve(), the executed
* process will be weakened to have execute permissions too.
*
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS if host os isn't Linux or OpenBSD
* @raise EINVAL if `execpromises` is used on Linux
* @raise EINVAL if `execpromises` on Linux isn't a subset of `promises`
*/
int pledge(const char *promises, const char *execpromises) {
int rc;
if (IsLinux()) {
rc = sys_pledge_linux(promises, execpromises);
} else {
rc = sys_pledge(promises, execpromises);
char *p, *q;
unsigned long ipromises, iexecpromises;
if (!(rc = ParsePromises(promises, &ipromises)) &&
!(rc = ParsePromises(execpromises, &iexecpromises))) {
if (IsLinux()) {
// copy exec and execnative from promises to execpromises
iexecpromises =
~(~iexecpromises | (~ipromises & ((1ul << PROMISE_EXEC) | //
(1ul << PROMISE_EXECNATIVE))));
// if bits are missing in execpromises that exist in promises
// then execpromises wouldn't be a monotonic access reduction
// this check only matters when exec / execnative are allowed
if ((ipromises & ~iexecpromises) &&
(~ipromises &
((1ul << PROMISE_EXEC) | (1ul << PROMISE_EXECNATIVE)))) {
STRACE("execpromises must be a subset of promises");
rc = einval();
} else {
rc = sys_pledge_linux(ipromises);
}
} else {
// openbsd only supports execnative and calls it exec
if ((p = strdup(promises))) {
FixupOpenbsdPromises(p);
if ((q = execpromises ? strdup(execpromises) : 0) || !execpromises) {
FixupOpenbsdPromises(q);
rc = sys_pledge(p, q);
free(q);
} else {
rc = -1;
}
free(p);
} else {
rc = -1;
}
}
if (!rc) {
SetPromises(promises);
__promises = ipromises;
__execpromises = iexecpromises;
}
}
STRACE("pledge(%#s, %#s) → %d% m", promises, execpromises, rc);

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/landlock.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/stat.h"
@ -25,7 +26,10 @@
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pr.h"
@ -126,10 +130,13 @@ static int sys_unveil_linux(const char *path, const char *permissions) {
if ((rc = sys_open(path, O_PATH | O_CLOEXEC, 0)) == -1) return rc;
pb.parent_fd = rc;
struct stat st;
if ((rc = fstat(pb.parent_fd, &st)) == -1) return err_close(rc, pb.parent_fd);
if (!S_ISDIR(st.st_mode)) pb.allowed_access &= FILE_BITS;
if ((rc = landlock_add_rule(State.fd, LANDLOCK_RULE_PATH_BENEATH, &pb, 0)))
if ((rc = sys_fstat(pb.parent_fd, &st)) == -1) {
return err_close(rc, pb.parent_fd);
}
if (!S_ISDIR(st.st_mode)) pb.allowed_access &= FILE_BITS;
if ((rc = landlock_add_rule(State.fd, LANDLOCK_RULE_PATH_BENEATH, &pb, 0))) {
return err_close(rc, pb.parent_fd);
}
sys_close(pb.parent_fd);
return rc;
}
@ -139,6 +146,7 @@ static int sys_unveil_linux(const char *path, const char *permissions) {
*/
int unveil(const char *path, const char *permissions) {
int rc;
__enable_tls();
if (IsLinux()) {
rc = sys_unveil_linux(path, permissions);
} else {

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall faccessat2,0xfffffffffffff1b7,globl

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall openat2,0xfffffffffffff1b5,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_faccessat2,0xfffffffffffff1b7,globl,hidden

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_openat2,0xfffffffffffff1b5,globl,hidden

View file

@ -385,9 +385,9 @@ scall fspick 0xfffffffffffff1b1 globl
scall pidfd_open 0xfffffffffffff1b2 globl
scall clone3 0xfffffffffffff1b3 globl
scall close_range 0xfffffffffffff1b4 globl
scall openat2 0xfffffffffffff1b5 globl # Linux 5.6
scall sys_openat2 0xfffffffffffff1b5 globl hidden # Linux 5.6
scall pidfd_getfd 0xfffffffffffff1b6 globl
scall faccessat2 0xfffffffffffff1b7 globl
scall sys_faccessat2 0xfffffffffffff1b7 globl hidden
scall process_madvise 0xfffffffffffff1b8 globl
scall epoll_pwait2 0xfffffffffffff1b9 globl
scall mount_setattr 0xfffffffffffff1ba globl