mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Rewrite Linux pledge() code so it can be a payload
It's now possible to build our pledge() polyfill as a dynamic shared object that can be injected into a glibc executable using LD_PRELOAD
This commit is contained in:
parent
7bd4179b9b
commit
0277d7d6e9
37 changed files with 1980 additions and 1600 deletions
|
@ -123,6 +123,7 @@ int killpg(int, int);
|
||||||
int link(const char *, const char *) dontthrow;
|
int link(const char *, const char *) dontthrow;
|
||||||
int linkat(int, const char *, int, const char *, int);
|
int linkat(int, const char *, int, const char *, int);
|
||||||
int madvise(void *, uint64_t, int);
|
int madvise(void *, uint64_t, int);
|
||||||
|
int memfd_create(const char *, unsigned int);
|
||||||
int mincore(void *, size_t, unsigned char *);
|
int mincore(void *, size_t, unsigned char *);
|
||||||
int mkdir(const char *, uint32_t);
|
int mkdir(const char *, uint32_t);
|
||||||
int mkdirat(int, const char *, uint32_t);
|
int mkdirat(int, const char *, uint32_t);
|
||||||
|
|
|
@ -188,11 +188,20 @@ o/$(MODE)/libc/calls/_timespec_frommicros.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-O2
|
-O2
|
||||||
|
|
||||||
o/$(MODE)/libc/calls/pledge.o \
|
o/$(MODE)/libc/calls/pledge-linux.o \
|
||||||
o/$(MODE)/libc/calls/unveil.o: \
|
o/$(MODE)/libc/calls/unveil.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-DSTACK_FRAME_UNLIMITED
|
-DSTACK_FRAME_UNLIMITED
|
||||||
|
|
||||||
|
# we want -Os because:
|
||||||
|
# it makes a big difference
|
||||||
|
# we need pic because:
|
||||||
|
# so it can be an LD_PRELOAD payload
|
||||||
|
o/$(MODE)/libc/calls/pledge-linux.o: \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-Os \
|
||||||
|
-fPIC
|
||||||
|
|
||||||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||||
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
|
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include "libc/bits/likely.h"
|
#include "libc/bits/likely.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/pledge.h"
|
||||||
|
#include "libc/calls/pledge.internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/syscall-nt.internal.h"
|
#include "libc/calls/syscall-nt.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
|
@ -30,8 +32,6 @@
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
int sys_pledge_linux(unsigned long);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces current process with program.
|
* Replaces current process with program.
|
||||||
*
|
*
|
||||||
|
@ -72,7 +72,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (IsLinux() && __execpromises && weaken(sys_pledge_linux)) {
|
if (IsLinux() && __execpromises && weaken(sys_pledge_linux)) {
|
||||||
rc = weaken(sys_pledge_linux)(__execpromises);
|
rc = weaken(sys_pledge_linux)(__execpromises, __pledge_mode, false);
|
||||||
}
|
}
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
rc = sys_execve(prog, argv, envp);
|
rc = sys_execve(prog, argv, envp);
|
||||||
|
|
|
@ -136,6 +136,6 @@ char *GetProgramExecutableName(void) {
|
||||||
return program_executable_name;
|
return program_executable_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *const GetProgramExecutableNameCtor[] initarray = {
|
/* const void *const GetProgramExecutableNameCtor[] initarray = { */
|
||||||
GetProgramExecutableName,
|
/* GetProgramExecutableName, */
|
||||||
};
|
/* }; */
|
||||||
|
|
35
libc/calls/memfd_create.c
Normal file
35
libc/calls/memfd_create.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*-*- 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"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates anonymous file.
|
||||||
|
*
|
||||||
|
* @param name is used for the `/proc/self/fd/FD` symlink
|
||||||
|
* @param flags can have `MFD_CLOEXEC`, `MFD_ALLOW_SEALING`
|
||||||
|
* @raise ENOSYS if not RHEL8+
|
||||||
|
*/
|
||||||
|
int memfd_create(const char *name, unsigned int flags) {
|
||||||
|
int rc;
|
||||||
|
rc = sys_memfd_create(name, flags);
|
||||||
|
STRACE("memfd_create(%#s, %#x) → %d% m", name, flags, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
66
libc/calls/parsepromises.c
Normal file
66
libc/calls/parsepromises.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*-*- 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/pledge.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
static int FindPromise(const char *name) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ARRAYLEN(kPledge); ++i) {
|
||||||
|
if (!strcasecmp(name, kPledge[i].name)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the arguments to pledge() into a bitmask.
|
||||||
|
*
|
||||||
|
* @return 0 on success, or -1 if invalid
|
||||||
|
*/
|
||||||
|
int ParsePromises(const char *promises, unsigned long *out) {
|
||||||
|
int rc = 0;
|
||||||
|
int promise;
|
||||||
|
unsigned long ipromises;
|
||||||
|
char *tok, *state, *start, buf[256];
|
||||||
|
if (promises) {
|
||||||
|
ipromises = -1;
|
||||||
|
if (memccpy(buf, promises, 0, sizeof(buf))) {
|
||||||
|
start = buf;
|
||||||
|
while ((tok = strtok_r(start, " \t\r\n", &state))) {
|
||||||
|
if ((promise = FindPromise(tok)) != -1) {
|
||||||
|
ipromises &= ~(1ULL << promise);
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ipromises = 0;
|
||||||
|
}
|
||||||
|
if (!rc) {
|
||||||
|
*out = ipromises;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
1625
libc/calls/pledge-linux.c
Normal file
1625
libc/calls/pledge-linux.c
Normal file
File diff suppressed because it is too large
Load diff
1568
libc/calls/pledge.c
1568
libc/calls/pledge.c
File diff suppressed because it is too large
Load diff
16
libc/calls/pledge.h
Normal file
16
libc/calls/pledge.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
enum PledgeMode {
|
||||||
|
kPledgeModeKillThread,
|
||||||
|
kPledgeModeKillProcess,
|
||||||
|
kPledgeModeErrno,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum PledgeMode __pledge_mode;
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_ */
|
|
@ -1,9 +1,20 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_PLEDGE_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_CALLS_PLEDGE_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_CALLS_PLEDGE_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_CALLS_PLEDGE_INTERNAL_H_
|
||||||
|
#include "libc/calls/pledge.h"
|
||||||
|
#include "libc/intrin/promises.internal.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
int ParsePromises(const char *, unsigned long *);
|
struct Pledges {
|
||||||
|
const char *name;
|
||||||
|
const uint16_t *syscalls;
|
||||||
|
const size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
hidden extern const struct Pledges kPledge[PROMISE_LEN_];
|
||||||
|
|
||||||
|
int sys_pledge_linux(unsigned long, enum PledgeMode, bool) hidden;
|
||||||
|
int ParsePromises(const char *, unsigned long *) hidden;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/getconsolectrlevent.internal.h"
|
#include "libc/calls/getconsolectrlevent.internal.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
@ -39,7 +41,7 @@ static textwindows inline bool HasWorkingConsole(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends signal to this process.
|
* Sends signal to this thread.
|
||||||
*
|
*
|
||||||
* @param sig can be SIGALRM, SIGINT, SIGTERM, SIGKILL, etc.
|
* @param sig can be SIGALRM, SIGINT, SIGTERM, SIGKILL, etc.
|
||||||
* @return 0 on success or -1 w/ errno
|
* @return 0 on success or -1 w/ errno
|
||||||
|
@ -56,8 +58,7 @@ int raise(int sig) {
|
||||||
x = 1 / x;
|
x = 1 / x;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
// XXX: should be tkill() or tgkill() on linux
|
rc = sys_tkill(gettid(), sig, 0);
|
||||||
rc = sys_kill(getpid(), sig, 1);
|
|
||||||
} else {
|
} else {
|
||||||
if (HasWorkingConsole() && (event = GetConsoleCtrlEvent(sig)) != -1) {
|
if (HasWorkingConsole() && (event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||||
// XXX: MSDN says "If this parameter is zero, the signal is
|
// XXX: MSDN says "If this parameter is zero, the signal is
|
||||||
|
|
|
@ -290,9 +290,9 @@ int sys_unveil_linux(const char *path, const char *permissions) {
|
||||||
* possible to use opendir() and go fishing for paths which weren't
|
* possible to use opendir() and go fishing for paths which weren't
|
||||||
* previously known.
|
* previously known.
|
||||||
*
|
*
|
||||||
* 5. Use ftruncate() rather than truncate(). One of the backdoors with
|
* 5. Use ftruncate() rather than truncate(). One issue Landlock hasn't
|
||||||
* Landlock is it currently can't restrict truncate() and setxattr()
|
* addressed yet is restrictions over truncate() and setxattr() which
|
||||||
* which permits certain kinds of modifications to files outside the
|
* could permit certain kinds of modifications to files outside the
|
||||||
* sandbox. When your policy is committed, we install a SECCOMP BPF
|
* sandbox. When your policy is committed, we install a SECCOMP BPF
|
||||||
* filter to disable those calls, however similar trickery may be
|
* filter to disable those calls, however similar trickery may be
|
||||||
* possible through other unaddressed calls like ioctl(). Using the
|
* possible through other unaddressed calls like ioctl(). Using the
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/promises.internal.h"
|
||||||
#include "libc/nexgen32e/vendor.internal.h"
|
#include "libc/nexgen32e/vendor.internal.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -39,11 +40,18 @@ privileged wontreturn void _Exit(int exitcode) {
|
||||||
int i;
|
int i;
|
||||||
STRACE("_Exit(%d)", exitcode);
|
STRACE("_Exit(%d)", exitcode);
|
||||||
if (!IsWindows() && !IsMetal()) {
|
if (!IsWindows() && !IsMetal()) {
|
||||||
asm volatile("syscall"
|
// On Linux _Exit1 (exit) must be called in pledge("") mode. If we
|
||||||
: /* no outputs */
|
// call _Exit (exit_group) when we haven't used pledge("stdio") then
|
||||||
: "a"(__NR_exit_group), "D"(exitcode)
|
// it'll terminate the process instead. On OpenBSD we must not call
|
||||||
: "rcx", "r11", "memory");
|
// _Exit1 (__threxit) because only _Exit (exit) is whitelisted when
|
||||||
// this should only be possible on Linux in a pledge ultra sandbox
|
// operating in pledge("") mode.
|
||||||
|
if (!(IsLinux() && !PLEDGED(STDIO))) {
|
||||||
|
asm volatile("syscall"
|
||||||
|
: /* no outputs */
|
||||||
|
: "a"(__NR_exit_group), "D"(exitcode)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
}
|
||||||
|
// Inline _Exit1() just in case _Exit() isn't allowed by pledge()
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: /* no outputs */
|
: /* no outputs */
|
||||||
: "a"(__NR_exit), "D"(exitcode)
|
: "a"(__NR_exit), "D"(exitcode)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/promises.internal.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
|
@ -35,6 +36,12 @@ privileged wontreturn void _Exit1(int rc) {
|
||||||
struct WinThread *wt;
|
struct WinThread *wt;
|
||||||
STRACE("_Exit1(%d)", rc);
|
STRACE("_Exit1(%d)", rc);
|
||||||
if (!IsWindows() && !IsMetal()) {
|
if (!IsWindows() && !IsMetal()) {
|
||||||
|
if (IsOpenbsd() && !PLEDGED(STDIO)) {
|
||||||
|
asm volatile("syscall"
|
||||||
|
: /* no outputs */
|
||||||
|
: "a"(__NR_exit), "D"(rc)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
}
|
||||||
asm volatile("xor\t%%r10d,%%r10d\n\t"
|
asm volatile("xor\t%%r10d,%%r10d\n\t"
|
||||||
"syscall"
|
"syscall"
|
||||||
: /* no outputs */
|
: /* no outputs */
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/pledge.h"
|
||||||
#include "libc/intrin/promises.internal.h"
|
#include "libc/intrin/promises.internal.h"
|
||||||
|
|
||||||
// XXX: should be inherited thread local
|
// XXX: should be inherited thread local
|
||||||
unsigned __pledge_mode;
|
// see also sys_pledge_linux() which is 100% pure
|
||||||
|
enum PledgeMode __pledge_mode;
|
||||||
unsigned long __promises;
|
unsigned long __promises;
|
||||||
unsigned long __execpromises;
|
unsigned long __execpromises;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define PROMISE_PROT_EXEC 18
|
#define PROMISE_PROT_EXEC 18
|
||||||
#define PROMISE_VMINFO 19
|
#define PROMISE_VMINFO 19
|
||||||
#define PROMISE_TMPPATH 20
|
#define PROMISE_TMPPATH 20
|
||||||
|
#define PROMISE_LEN_ 21
|
||||||
|
|
||||||
#define PLEDGED(x) ((~__promises >> PROMISE_##x) & 1)
|
#define PLEDGED(x) ((~__promises >> PROMISE_##x) & 1)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern intptr_t __oldstack; /* CRT */
|
||||||
extern uint64_t __nosync; /* SYS */
|
extern uint64_t __nosync; /* SYS */
|
||||||
extern _Atomic(int) __ftrace; /* SYS */
|
extern _Atomic(int) __ftrace; /* SYS */
|
||||||
extern _Atomic(int) __strace; /* SYS */
|
extern _Atomic(int) __strace; /* SYS */
|
||||||
extern uint32_t __pledge_mode; /* SYS */
|
|
||||||
extern char *program_invocation_name; /* RII */
|
extern char *program_invocation_name; /* RII */
|
||||||
extern char *program_invocation_short_name; /* RII */
|
extern char *program_invocation_short_name; /* RII */
|
||||||
extern uint64_t __syscount; /* RII */
|
extern uint64_t __syscount; /* RII */
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.internal.inc"
|
|
||||||
.scall memfd_create,0xfffffffffffff13f,globl
|
|
2
libc/sysv/calls/sys_memfd_create.s
Normal file
2
libc/sysv/calls/sys_memfd_create.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "o/libc/sysv/macros.internal.inc"
|
||||||
|
.scall sys_memfd_create,0xfffffffffffff13f,globl,hidden
|
|
@ -417,14 +417,6 @@ syscon at AT_REMOVEDIR 0x0200 0x80 0x0800 8 0x800 0x0200 # faked
|
||||||
syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0 # performs check using effective uid/gid; unnecessary nt
|
syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0 # performs check using effective uid/gid; unnecessary nt
|
||||||
syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc.
|
syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc.
|
||||||
|
|
||||||
# memfd_create() flags
|
|
||||||
#
|
|
||||||
# Unsupported flags are encoded as 0.
|
|
||||||
#
|
|
||||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
|
||||||
syscon memfd MFD_CLOEXEC 1 0 0 0 0 0
|
|
||||||
syscon memfd MFD_ALLOW_SEALING 2 0 0 0 0 0
|
|
||||||
|
|
||||||
# utimensat() special values
|
# utimensat() special values
|
||||||
#
|
#
|
||||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon termios,CANBSIZ,255,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon misc,IPPORT_RESERVED,0x0400,0x0400,0x0400,0x0400,0x0400,0x0400
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon memfd,MFD_ALLOW_SEALING,2,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon memfd,MFD_CLOEXEC,1,0,0,0,0,0
|
|
|
@ -1,16 +1,7 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_MFD_H_
|
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_MFD_H_
|
||||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_MFD_H_
|
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_MFD_H_
|
||||||
#include "libc/runtime/symbolic.h"
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
||||||
COSMOPOLITAN_C_START_
|
|
||||||
|
|
||||||
extern const unsigned int MFD_CLOEXEC;
|
#define MFD_CLOEXEC 1
|
||||||
extern const unsigned int MFD_ALLOW_SEALING;
|
#define MFD_ALLOW_SEALING 2
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
||||||
|
|
||||||
#define MFD_CLOEXEC SYMBOLIC(MFD_CLOEXEC)
|
|
||||||
#define MFD_ALLOW_SEALING SYMBOLIC(MFD_ALLOW_SEALING)
|
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_MFD_H_ */
|
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_MFD_H_ */
|
||||||
|
|
|
@ -350,7 +350,7 @@ scall sched_getattr 0xfffffffffffff13b globl # ├─ karen sandler requires s
|
||||||
scall renameat2 0xfffffffffffff13c globl # └─ debian founder ian murdock found strangled with vacuum cord
|
scall renameat2 0xfffffffffffff13c globl # └─ debian founder ian murdock found strangled with vacuum cord
|
||||||
#scall seccomp 0xfffffffffffff13d globl # wrapped manually
|
#scall seccomp 0xfffffffffffff13d globl # wrapped manually
|
||||||
scall sys_getrandom 0xfff00723321f413e globl hidden # Linux 3.17+ and getentropy() on XNU/OpenBSD, coming to NetBSD in 9.2
|
scall sys_getrandom 0xfff00723321f413e globl hidden # Linux 3.17+ and getentropy() on XNU/OpenBSD, coming to NetBSD in 9.2
|
||||||
scall memfd_create 0xfffffffffffff13f globl # wut
|
scall sys_memfd_create 0xfffffffffffff13f globl hidden
|
||||||
scall kexec_file_load 0xfffffffffffff140 globl
|
scall kexec_file_load 0xfffffffffffff140 globl
|
||||||
scall bpf 0xfffffffffffff141 globl
|
scall bpf 0xfffffffffffff141 globl
|
||||||
scall execveat 0xfffffffffffff142 globl
|
scall execveat 0xfffffffffffff142 globl
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/pledge.internal.h"
|
||||||
#include "libc/calls/struct/seccomp.h"
|
#include "libc/calls/struct/seccomp.h"
|
||||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/promises.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/sysv/consts/af.h"
|
#include "libc/sysv/consts/af.h"
|
||||||
|
@ -58,7 +60,7 @@ void SetUp(void) {
|
||||||
TEST(pledge, testSoftError) {
|
TEST(pledge, testSoftError) {
|
||||||
if (IsOpenbsd()) return;
|
if (IsOpenbsd()) return;
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
__pledge_mode = SECCOMP_RET_ERRNO | EPERM;
|
__pledge_mode = kPledgeModeErrno;
|
||||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||||
_Exit(7);
|
_Exit(7);
|
||||||
|
@ -67,27 +69,27 @@ TEST(pledge, testSoftError) {
|
||||||
|
|
||||||
TEST(pledge, testKillThreadMode) {
|
TEST(pledge, testKillThreadMode) {
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
__pledge_mode = SECCOMP_RET_KILL_THREAD;
|
__pledge_mode = kPledgeModeKillThread;
|
||||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
TERMS(IsOpenbsd() ? SIGABRT : SIGSYS);
|
TERMS(SIGABRT);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge, testKillProcessMode) {
|
TEST(pledge, testKillProcessMode) {
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
__pledge_mode = SECCOMP_RET_KILL_PROCESS;
|
__pledge_mode = kPledgeModeKillProcess;
|
||||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
TERMS(IsOpenbsd() ? SIGABRT : SIGSYS);
|
TERMS(SIGABRT);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge, testLogMessage_onSoftyMode) {
|
TEST(pledge, testLogMessage_inSoftyMode) {
|
||||||
if (IsOpenbsd()) return;
|
if (IsOpenbsd()) return;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
char msg[64] = {0};
|
char msg[64] = {0};
|
||||||
ASSERT_SYS(0, 0, pipe(fds));
|
ASSERT_SYS(0, 0, pipe(fds));
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
__pledge_mode = SECCOMP_RET_ERRNO | EPERM;
|
__pledge_mode = kPledgeModeErrno;
|
||||||
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
||||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||||
|
@ -105,11 +107,11 @@ TEST(pledge, testLogMessage_onKillProcess) {
|
||||||
char msg[64] = {0};
|
char msg[64] = {0};
|
||||||
ASSERT_SYS(0, 0, pipe(fds));
|
ASSERT_SYS(0, 0, pipe(fds));
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
__pledge_mode = SECCOMP_RET_KILL;
|
__pledge_mode = kPledgeModeKillThread;
|
||||||
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
||||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
TERMS(IsOpenbsd() ? SIGABRT : SIGSYS);
|
TERMS(SIGABRT);
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
read(fds[0], msg, sizeof(msg));
|
read(fds[0], msg, sizeof(msg));
|
||||||
close(fds[0]);
|
close(fds[0]);
|
||||||
|
@ -118,7 +120,7 @@ TEST(pledge, testLogMessage_onKillProcess) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge, testNoLogPossibleSadly_becausePledgedExec) {
|
TEST(pledge, testNoLogOrAbrtsignoPossibleSadly_becausePledgedExec) {
|
||||||
int fds[2];
|
int fds[2];
|
||||||
char msg[64] = {0};
|
char msg[64] = {0};
|
||||||
ASSERT_SYS(0, 0, pipe(fds));
|
ASSERT_SYS(0, 0, pipe(fds));
|
||||||
|
@ -132,3 +134,11 @@ TEST(pledge, testNoLogPossibleSadly_becausePledgedExec) {
|
||||||
close(fds[0]);
|
close(fds[0]);
|
||||||
ASSERT_STREQ("", msg);
|
ASSERT_STREQ("", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(pledge, testDoublePledge_isFine) {
|
||||||
|
SPAWN(fork);
|
||||||
|
__pledge_mode = kPledgeModeKillThread;
|
||||||
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
|
EXITS(0);
|
||||||
|
}
|
||||||
|
|
|
@ -60,10 +60,6 @@ STATIC_YOINK("zip_uri_support");
|
||||||
|
|
||||||
char testlib_enable_tmp_setup_teardown;
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
__attribute__((__constructor__)) static void init(void) {
|
|
||||||
__pledge_mode = SECCOMP_RET_ERRNO | EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnSig(int sig) {
|
void OnSig(int sig) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -89,6 +85,7 @@ void SetUp(void) {
|
||||||
if (!__is_linux_2_6_23() && !IsOpenbsd()) exit(0);
|
if (!__is_linux_2_6_23() && !IsOpenbsd()) exit(0);
|
||||||
ASSERT_SYS(0, 0, extract("/zip/life.elf", "life.elf", 0755));
|
ASSERT_SYS(0, 0, extract("/zip/life.elf", "life.elf", 0755));
|
||||||
ASSERT_SYS(0, 0, extract("/zip/sock.elf", "sock.elf", 0755));
|
ASSERT_SYS(0, 0, extract("/zip/sock.elf", "sock.elf", 0755));
|
||||||
|
__pledge_mode = kPledgeModeErrno;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge, default_allowsExit) {
|
TEST(pledge, default_allowsExit) {
|
||||||
|
@ -112,11 +109,13 @@ TEST(pledge, default_allowsExit) {
|
||||||
EXPECT_SYS(0, 0, munmap(job, FRAMESIZE));
|
EXPECT_SYS(0, 0, munmap(job, FRAMESIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
TEST(pledge, execpromises_notok) {
|
TEST(pledge, execpromises_notok) {
|
||||||
if (IsOpenbsd()) return; // b/c testing linux bpf
|
if (IsOpenbsd()) return; // b/c testing linux bpf
|
||||||
int ws, pid;
|
int ws, pid;
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
|
__pledge_mode = kPledgeModeErrno;
|
||||||
ASSERT_SYS(0, 0, pledge("stdio rpath exec", "stdio"));
|
ASSERT_SYS(0, 0, pledge("stdio rpath exec", "stdio"));
|
||||||
execl("sock.elf", "sock.elf", 0);
|
execl("sock.elf", "sock.elf", 0);
|
||||||
_Exit(127);
|
_Exit(127);
|
||||||
|
@ -157,8 +156,8 @@ TEST(pledge, stdio_forbidsOpeningPasswd1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge, stdio_forbidsOpeningPasswd2) {
|
TEST(pledge, stdio_forbidsOpeningPasswd2) {
|
||||||
if (!IsOpenbsd()) return;
|
|
||||||
int ws, pid;
|
int ws, pid;
|
||||||
|
__pledge_mode = kPledgeModeKillProcess;
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||||
|
@ -558,7 +557,6 @@ TEST(pledge_linux, execpromisesIsSuperset_notPossible) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge_openbsd, execpromises_notok) {
|
TEST(pledge_openbsd, execpromises_notok) {
|
||||||
if (!IsOpenbsd()) return;
|
|
||||||
int ws, pid;
|
int ws, pid;
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
|
@ -567,8 +565,15 @@ TEST(pledge_openbsd, execpromises_notok) {
|
||||||
_Exit(127);
|
_Exit(127);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, wait(&ws));
|
EXPECT_NE(-1, wait(&ws));
|
||||||
EXPECT_TRUE(WIFSIGNALED(ws));
|
if (IsOpenbsd()) {
|
||||||
EXPECT_EQ(SIGABRT, WTERMSIG(ws));
|
EXPECT_TRUE(WIFSIGNALED(ws));
|
||||||
|
EXPECT_EQ(SIGABRT, WTERMSIG(ws));
|
||||||
|
} else {
|
||||||
|
// linux can't be consistent here since we pledged exec
|
||||||
|
// so we return EPERM instead and sock.elf passes along
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
|
EXPECT_EQ(128 + EPERM, WEXITSTATUS(ws));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pledge_openbsd, bigSyscalls) {
|
TEST(pledge_openbsd, bigSyscalls) {
|
||||||
|
@ -658,3 +663,4 @@ BENCH(pledge, bench) {
|
||||||
}
|
}
|
||||||
wait(0);
|
wait(0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -373,7 +373,7 @@ TEST(unveil, usedTwice_forbidden_worksWithPledge) {
|
||||||
ASSERT_NE(-1, wait(&ws));
|
ASSERT_NE(-1, wait(&ws));
|
||||||
ASSERT_TRUE(*gotsome);
|
ASSERT_TRUE(*gotsome);
|
||||||
ASSERT_TRUE(WIFSIGNALED(ws));
|
ASSERT_TRUE(WIFSIGNALED(ws));
|
||||||
ASSERT_EQ(IsOpenbsd() ? SIGABRT : SIGSYS, WTERMSIG(ws));
|
ASSERT_EQ(SIGABRT, WTERMSIG(ws));
|
||||||
EXPECT_SYS(0, 0, munmap(gotsome, FRAMESIZE));
|
EXPECT_SYS(0, 0, munmap(gotsome, FRAMESIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ elif [ "$1" = ape_assimilated_test_suite ]; then
|
||||||
startit ape assimilated curl.com
|
startit ape assimilated curl.com
|
||||||
cp o//examples/curl.com $t/assimilated
|
cp o//examples/curl.com $t/assimilated
|
||||||
o//tool/build/assimilate.com $t/assimilated/curl.com
|
o//tool/build/assimilate.com $t/assimilated/curl.com
|
||||||
[ "$(o/$m/tool/build/pledge.com -p 'stdio inet dns' $t/assimilated/curl.com https://justine.lol/hello.txt)" = "hello world" ]
|
[ "$(o/$m/tool/build/pledge.com -p 'stdio rpath inet dns' $t/assimilated/curl.com https://justine.lol/hello.txt)" = "hello world" ]
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
elif [ "$1" = ape_native_test_suite ]; then
|
elif [ "$1" = ape_native_test_suite ]; then
|
||||||
|
@ -131,7 +131,7 @@ elif [ "$1" = ape_native_test_suite ]; then
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit ape native curl.com
|
startit ape native curl.com
|
||||||
[ "$(o/$m/tool/build/pledge.com -p 'stdio inet dns' o/$m/examples/curl.com https://justine.lol/hello.txt)" = "hello world" ]
|
[ "$(o/$m/tool/build/pledge.com -p 'stdio rpath inet dns' o/$m/examples/curl.com https://justine.lol/hello.txt)" = "hello world" ]
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
elif [ "$1" = setuid_test_suite ]; then
|
elif [ "$1" = setuid_test_suite ]; then
|
||||||
|
@ -146,23 +146,23 @@ elif [ "$1" = setuid_test_suite ]; then
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit setuid curl.com
|
startit setuid curl.com
|
||||||
[ "$($t/pledge.com -p 'stdio inet dns' o/$m/examples/curl.com https://justine.lol/hello.txt)" = "hello world" ]
|
[ "$($t/pledge.com -p 'stdio rpath inet dns' o/$m/examples/curl.com https://justine.lol/hello.txt)" = "hello world" ]
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit setuid getuid
|
startit setuid getuid
|
||||||
[ "$($t/pledge.com -pstdio o/$m/examples/printargs.com 2>&1 | grep getuid | grep -o [[:digit:]]*)" = "$(id -u)" ]
|
[ "$($t/pledge.com -p 'stdio rpath proc tty' o/$m/examples/printargs.com 2>&1 | grep getuid | grep -o [[:digit:]]*)" = "$(id -u)" ]
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit setuid geteuid
|
startit setuid geteuid
|
||||||
[ "$($t/pledge.com -pstdio o/$m/examples/printargs.com 2>&1 | grep geteuid | grep -o [[:digit:]]*)" = "$(id -u)" ]
|
[ "$($t/pledge.com -p 'stdio rpath proc tty' o/$m/examples/printargs.com 2>&1 | grep geteuid | grep -o [[:digit:]]*)" = "$(id -u)" ]
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit setuid no capabilities
|
startit setuid no capabilities
|
||||||
[ "$($t/pledge.com -pstdio o/$m/examples/printargs.com 2>&1 | grep CAP_ | wc -l)" = 0 ]
|
[ "$($t/pledge.com -p 'stdio rpath proc tty' o/$m/examples/printargs.com 2>&1 | grep CAP_ | wc -l)" = 0 ]
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit setuid maximum nice
|
startit setuid maximum nice
|
||||||
$t/pledge.com -np 'stdio proc' o/$m/examples/printargs.com 2>&1 | grep SCHED_IDLE >/dev/null
|
$t/pledge.com -np 'stdio rpath proc tty' o/$m/examples/printargs.com 2>&1 | grep SCHED_IDLE >/dev/null
|
||||||
checkem
|
checkem
|
||||||
|
|
||||||
startit setuid chroot
|
startit setuid chroot
|
||||||
|
|
|
@ -82,7 +82,7 @@ function UnixTest()
|
||||||
unix.close(reader)
|
unix.close(reader)
|
||||||
pid, ws = assert(unix.wait())
|
pid, ws = assert(unix.wait())
|
||||||
assert(unix.WIFSIGNALED(ws))
|
assert(unix.WIFSIGNALED(ws))
|
||||||
assert(unix.WTERMSIG(ws) == unix.SIGSYS)
|
assert(unix.WTERMSIG(ws) == unix.SIGABRT)
|
||||||
elseif GetHostOs() == "OPENBSD" then
|
elseif GetHostOs() == "OPENBSD" then
|
||||||
if assert(unix.fork()) == 0 then
|
if assert(unix.fork()) == 0 then
|
||||||
assert(unix.pledge("stdio"))
|
assert(unix.pledge("stdio"))
|
||||||
|
|
8
third_party/chibicc/test/test.mk
vendored
8
third_party/chibicc/test/test.mk
vendored
|
@ -69,10 +69,10 @@ o/$(MODE)/third_party/chibicc/test/%.com.dbg: \
|
||||||
$(APE_NO_MODIFY_SELF)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(THIRD_PARTY_CHIBICC_TEST_OBJS): CC = $(CHIBICC)
|
o/$(MODE)/third_party/chibicc/test/%.o: \
|
||||||
$(THIRD_PARTY_CHIBICC_TEST_OBJS): $(CHIBICC)
|
third_party/chibicc/test/%.c \
|
||||||
|
$(CHIBICC)
|
||||||
.PRECIOUS: $(THIRD_PARTY_CHIBICC_TEST_OBJS)
|
@$(COMPILE) -AOBJECTIFY.c $(CHIBICC) $(CHIBICC_FLAGS) $(OUTPUT_OPTION) -c $<
|
||||||
|
|
||||||
o/$(MODE)/third_party/chibicc/test/int128_test.o: QUOTA = -M1024m
|
o/$(MODE)/third_party/chibicc/test/int128_test.o: QUOTA = -M1024m
|
||||||
|
|
||||||
|
|
1
third_party/lua/lunix.c
vendored
1
third_party/lua/lunix.c
vendored
|
@ -21,6 +21,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/ioctl.h"
|
#include "libc/calls/ioctl.h"
|
||||||
#include "libc/calls/makedev.h"
|
#include "libc/calls/makedev.h"
|
||||||
|
#include "libc/calls/pledge.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/bpf.h"
|
#include "libc/calls/struct/bpf.h"
|
||||||
#include "libc/calls/struct/dirent.h"
|
#include "libc/calls/struct/dirent.h"
|
||||||
|
|
|
@ -117,6 +117,25 @@ o/$(MODE)/tool/build/printf.zip.o: o/$(MODE)/tool/build/printf
|
||||||
o/$(MODE)/tool/build/dd.zip.o: o/$(MODE)/tool/build/dd
|
o/$(MODE)/tool/build/dd.zip.o: o/$(MODE)/tool/build/dd
|
||||||
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -0 -B -Pbin $(OUTPUT_OPTION) $<
|
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -0 -B -Pbin $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
|
# we need pic because:
|
||||||
|
# so it can be an LD_PRELOAD payload
|
||||||
|
o/$(MODE)/tool/build/sandbox.o: \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-fPIC
|
||||||
|
|
||||||
|
o/$(MODE)/tool/build/sandbox.so: \
|
||||||
|
o/$(MODE)/tool/build/sandbox.o \
|
||||||
|
o/$(MODE)/libc/calls/pledge-linux.o \
|
||||||
|
o/$(MODE)/libc/sysv/restorert.o
|
||||||
|
@$(COMPILE) -ALINK.so \
|
||||||
|
$(CC) \
|
||||||
|
-s \
|
||||||
|
-shared \
|
||||||
|
-nostdlib \
|
||||||
|
-Wl,--gc-sections \
|
||||||
|
$(LINKARGS) \
|
||||||
|
$(OUTPUT_OPTION)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/tool/build
|
.PHONY: o/$(MODE)/tool/build
|
||||||
o/$(MODE)/tool/build: \
|
o/$(MODE)/tool/build: \
|
||||||
o/$(MODE)/tool/build/emucrt \
|
o/$(MODE)/tool/build/emucrt \
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/landlock.h"
|
#include "libc/calls/landlock.h"
|
||||||
|
#include "libc/calls/pledge.h"
|
||||||
#include "libc/calls/struct/rlimit.h"
|
#include "libc/calls/struct/rlimit.h"
|
||||||
#include "libc/calls/struct/sched_param.h"
|
#include "libc/calls/struct/sched_param.h"
|
||||||
#include "libc/calls/struct/seccomp.h"
|
#include "libc/calls/struct/seccomp.h"
|
||||||
|
@ -73,6 +74,7 @@ usage: pledge.com [-hnN] PROG ARGS...\n\
|
||||||
-u UID call setuid()\n\
|
-u UID call setuid()\n\
|
||||||
-c PATH call chroot()\n\
|
-c PATH call chroot()\n\
|
||||||
-v [PERM:]PATH call unveil(PATH, PERM[rwxc])\n\
|
-v [PERM:]PATH call unveil(PATH, PERM[rwxc])\n\
|
||||||
|
-k kill process rather than eperm'ing\n\
|
||||||
-n set maximum niceness\n\
|
-n set maximum niceness\n\
|
||||||
-D don't drop capabilities\n\
|
-D don't drop capabilities\n\
|
||||||
-N don't normalize file descriptors\n\
|
-N don't normalize file descriptors\n\
|
||||||
|
@ -118,6 +120,7 @@ int ParsePromises(const char *, unsigned long *);
|
||||||
|
|
||||||
int g_gflag;
|
int g_gflag;
|
||||||
int g_uflag;
|
int g_uflag;
|
||||||
|
int g_kflag;
|
||||||
int g_hflag;
|
int g_hflag;
|
||||||
bool g_nice;
|
bool g_nice;
|
||||||
bool g_noclose;
|
bool g_noclose;
|
||||||
|
@ -140,14 +143,16 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
g_promises = 0;
|
g_promises = 0;
|
||||||
g_fszquota = 256 * 1000 * 1000;
|
g_fszquota = 256 * 1000 * 1000;
|
||||||
g_proquota = GetCpuCount() * 100;
|
g_proquota = GetCpuCount() * 100;
|
||||||
g_fszquota = 4 * 1000 * 1000 * 1000;
|
|
||||||
g_memquota = 4L * 1024 * 1024 * 1024;
|
g_memquota = 4L * 1024 * 1024 * 1024;
|
||||||
if (!sysinfo(&si)) g_memquota = si.totalram;
|
if (!sysinfo(&si)) g_memquota = si.totalram;
|
||||||
while ((opt = getopt(argc, argv, "hnNp:u:g:c:C:D:P:M:F:v:")) != -1) {
|
while ((opt = getopt(argc, argv, "hnkNp:u:g:c:C:D:P:M:F:v:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'n':
|
case 'n':
|
||||||
g_nice = true;
|
g_nice = true;
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
g_kflag = true;
|
||||||
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
g_noclose = true;
|
g_noclose = true;
|
||||||
break;
|
break;
|
||||||
|
@ -453,10 +458,12 @@ void ApplyFilesystemPolicy(unsigned long ipromises) {
|
||||||
|
|
||||||
if (~ipromises & (1ul << PROMISE_PROT_EXEC)) {
|
if (~ipromises & (1ul << PROMISE_PROT_EXEC)) {
|
||||||
if (UnveilIfExists("/usr/bin/ape", "rx") == -1) {
|
if (UnveilIfExists("/usr/bin/ape", "rx") == -1) {
|
||||||
UnveilIfExists(xjoinpaths(firstnonnull(getenv("TMPDIR"),
|
if ((p = getenv("TMPDIR"))) {
|
||||||
firstnonnull(getenv("HOME"), ".")),
|
UnveilIfExists(xjoinpaths(p, ".ape"), "rx");
|
||||||
".ape"),
|
}
|
||||||
"rx");
|
if ((p = getenv("HOME"))) {
|
||||||
|
UnveilIfExists(xjoinpaths(p, ".ape"), "rx");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,7 +678,11 @@ int main(int argc, char *argv[]) {
|
||||||
// model. we do this becasue it's only possible to have sigsys print
|
// model. we do this becasue it's only possible to have sigsys print
|
||||||
// crash messages if we're not pledging exec, which is what this tool
|
// crash messages if we're not pledging exec, which is what this tool
|
||||||
// always has to do currently.
|
// always has to do currently.
|
||||||
__pledge_mode = SECCOMP_RET_ERRNO | EPERM;
|
if (g_kflag) {
|
||||||
|
__pledge_mode = kPledgeModeKillProcess;
|
||||||
|
} else {
|
||||||
|
__pledge_mode = kPledgeModeErrno;
|
||||||
|
}
|
||||||
|
|
||||||
// apply sandbox
|
// apply sandbox
|
||||||
if (pledge(g_promises, g_promises) == -1) {
|
if (pledge(g_promises, g_promises) == -1) {
|
||||||
|
|
28
tool/build/sandbox.c
Normal file
28
tool/build/sandbox.c
Normal 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/pledge.h"
|
||||||
|
#include "libc/calls/pledge.internal.h"
|
||||||
|
#include "libc/intrin/promises.internal.h"
|
||||||
|
|
||||||
|
hidden char __privileged_start;
|
||||||
|
hidden char __privileged_end;
|
||||||
|
|
||||||
|
__attribute__((__constructor__)) void InitializeSandbox(void) {
|
||||||
|
sys_pledge_linux(~(1ul << PROMISE_STDIO), kPledgeModeErrno, false);
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/ioctl.h"
|
#include "libc/calls/ioctl.h"
|
||||||
|
#include "libc/calls/pledge.h"
|
||||||
#include "libc/calls/struct/dirent.h"
|
#include "libc/calls/struct/dirent.h"
|
||||||
#include "libc/calls/struct/flock.h"
|
#include "libc/calls/struct/flock.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
|
@ -6587,7 +6588,7 @@ static void UnveilRedbean(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int EnableSandbox(void) {
|
static int EnableSandbox(void) {
|
||||||
__pledge_mode = SECCOMP_RET_ERRNO | EPERM;
|
__pledge_mode = kPledgeModeErrno;
|
||||||
switch (sandboxed) {
|
switch (sandboxed) {
|
||||||
case 0:
|
case 0:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue