mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Refactor pledge() to be more configurable
The earlier iterations did too much guesswork when it came to things like stderr logging and syscall origin verification. This change will make things more conformant to existing practices. The __pledge_mode extension now can be configured in a better way. There's also a new `-q` flag added to pledge.com, e.g. o//tool/build/pledge.com -qv. ls Is a good way to disable warnings about `tty` access attempts.
This commit is contained in:
parent
6b8b58fdf5
commit
625aa365f1
36 changed files with 203 additions and 168 deletions
|
@ -30,12 +30,8 @@ o/%.zip.o: o/% ; @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FL
|
|||
o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.o: o/$(MODE)/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.s: %.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.s: o/$(MODE)/%.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.o: %.f ; @$(COMPILE) -AOBJECTIFY.f $(OBJECTIFY.f) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.o: %.F ; @$(COMPILE) -AOBJECTIFY.F $(OBJECTIFY.F) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.ss: %.c ; @$(COMPILE) -ACOMPILE.c $(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.ss: o/$(MODE)/%.c ; @$(COMPILE) -AOBJECTIFY.s $(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.h: %.c ; @$(COMPILE) -AAMALGAMATE $(PREPROCESS) $(OUTPUT_OPTION) -fdirectives-only -P $<
|
||||
o/$(MODE)/%.h: o/$(MODE)/%.c ; @$(COMPILE) -AAMALGAMATE $(PREPROCESS) $(OUTPUT_OPTION) -fdirectives-only -P $<
|
||||
o/$(MODE)/%.o: %.S ; @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
|
||||
|
|
|
@ -72,7 +72,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && weaken(sys_pledge_linux)) {
|
||||
rc = weaken(sys_pledge_linux)(__execpromises, __pledge_mode, false);
|
||||
rc = weaken(sys_pledge_linux)(__execpromises, __pledge_mode);
|
||||
}
|
||||
if (!rc) {
|
||||
rc = sys_execve(prog, argv, envp);
|
||||
|
|
|
@ -903,15 +903,13 @@ static privileged int SigProcMask(int how, int64_t set, int64_t *old) {
|
|||
|
||||
static privileged void KillThisProcess(void) {
|
||||
int ax;
|
||||
struct sigaction dfl = {.sa_sigaction = SIG_DFL};
|
||||
if (!SigAction(Sigabrt, &dfl, 0)) {
|
||||
SigProcMask(Sig_Setmask, -1, 0);
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_linux_kill), "D"(GetPid()), "S"(Sigabrt)
|
||||
: "rcx", "r11", "memory");
|
||||
SigProcMask(Sig_Setmask, 0, 0);
|
||||
}
|
||||
SigAction(Sigabrt, &(struct sigaction){0}, 0);
|
||||
SigProcMask(Sig_Setmask, -1, 0);
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_linux_kill), "D"(GetPid()), "S"(Sigabrt)
|
||||
: "rcx", "r11", "memory");
|
||||
SigProcMask(Sig_Setmask, 0, 0);
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_linux_exit_group), "D"(128 + Sigabrt)
|
||||
|
@ -920,15 +918,13 @@ static privileged void KillThisProcess(void) {
|
|||
|
||||
static privileged void KillThisThread(void) {
|
||||
int ax;
|
||||
struct sigaction dfl = {.sa_sigaction = SIG_DFL};
|
||||
if (!SigAction(Sigabrt, &dfl, 0)) {
|
||||
SigProcMask(Sig_Setmask, -1, 0);
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_linux_tkill), "D"(GetTid()), "S"(Sigabrt)
|
||||
: "rcx", "r11", "memory");
|
||||
SigProcMask(Sig_Setmask, 0, 0);
|
||||
}
|
||||
SigAction(Sigabrt, &(struct sigaction){0}, 0);
|
||||
SigProcMask(Sig_Setmask, -1, 0);
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_linux_tkill), "D"(GetTid()), "S"(Sigabrt)
|
||||
: "rcx", "r11", "memory");
|
||||
SigProcMask(Sig_Setmask, 0, 0);
|
||||
asm volatile("syscall"
|
||||
: /* no outputs */
|
||||
: "a"(__NR_linux_exit), "D"(128 + Sigabrt)
|
||||
|
@ -959,10 +955,9 @@ static privileged int HasSyscall(struct Pledges *p, uint16_t n) {
|
|||
}
|
||||
|
||||
static privileged void OnSigSys(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||
int i, ok;
|
||||
bool found;
|
||||
char ord[17], rip[17];
|
||||
enum PledgeMode mode = si->si_errno;
|
||||
int i, ok, mode = si->si_errno;
|
||||
ctx->uc_mcontext.rax = -Eperm;
|
||||
FixCpy(ord, si->si_syscall, 12);
|
||||
HexCpy(rip, ctx->uc_mcontext.rip);
|
||||
|
@ -978,11 +973,11 @@ static privileged void OnSigSys(int sig, siginfo_t *si, ucontext_t *ctx) {
|
|||
Log("error: bad syscall (", GetSyscallName(si->si_syscall), " ord=", ord,
|
||||
" rip=", rip, ")\n", 0);
|
||||
}
|
||||
switch (mode) {
|
||||
case kPledgeModeKillProcess:
|
||||
switch (mode & PLEDGE_PENALTY_MASK) {
|
||||
case PLEDGE_PENALTY_KILL_PROCESS:
|
||||
KillThisProcess();
|
||||
// fallthrough
|
||||
case kPledgeModeKillThread:
|
||||
case PLEDGE_PENALTY_KILL_THREAD:
|
||||
KillThisThread();
|
||||
unreachable;
|
||||
default:
|
||||
|
@ -1016,6 +1011,7 @@ static privileged void AppendFilter(struct Filter *f, struct sock_filter *p,
|
|||
// - kill(getpid(), SIGABRT) to abort process
|
||||
// - tkill(gettid(), SIGABRT) to abort thread
|
||||
// - sigaction(SIGABRT) to force default signal handler
|
||||
// - sigreturn() to return from signal handler
|
||||
// - sigprocmask() to force signal delivery
|
||||
//
|
||||
static privileged void AllowMonitor(struct Filter *f) {
|
||||
|
@ -1044,6 +1040,7 @@ static privileged void AllowMonitor(struct Filter *f) {
|
|||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, Sigabrt, 0, 1),
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_sigreturn, 1, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_sigprocmask, 0, 1),
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
|
@ -1897,17 +1894,12 @@ static privileged void AppendPledge(struct Filter *f, //
|
|||
* Installs SECCOMP BPF filter on Linux thread.
|
||||
*
|
||||
* @param ipromises is inverted integer bitmask of pledge() promises
|
||||
* @param mode configures the course of action on sandbox violations
|
||||
* @param want_msyscall if set will cause syscall origin checking to be
|
||||
* enabled, but only if `exec` hasn't been pledged
|
||||
* @return 0 on success, or negative error number on error
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
privileged int sys_pledge_linux(unsigned long ipromises, //
|
||||
enum PledgeMode mode, //
|
||||
bool want_msyscall) { //
|
||||
privileged int sys_pledge_linux(unsigned long ipromises, int mode) {
|
||||
struct Filter f;
|
||||
int i, e, rc = -1;
|
||||
struct sock_filter sf[1] = {BPF_STMT(BPF_RET | BPF_K, 0)};
|
||||
|
@ -1921,9 +1913,6 @@ privileged int sys_pledge_linux(unsigned long ipromises, //
|
|||
// when _Exit() gets called since we need to fallback to _Exit1()
|
||||
AppendFilter(&f, PLEDGE(kFilterIgnoreExitGroup));
|
||||
}
|
||||
if (want_msyscall && !(~ipromises & (1ul << PROMISE_EXEC))) {
|
||||
AppendOriginVerification(&f);
|
||||
}
|
||||
AppendPledge(&f, PLEDGE(kPledgeDefault));
|
||||
for (i = 0; i < ARRAYLEN(kPledge); ++i) {
|
||||
if (~ipromises & (1ul << i)) {
|
||||
|
@ -1936,25 +1925,9 @@ privileged int sys_pledge_linux(unsigned long ipromises, //
|
|||
}
|
||||
|
||||
// now determine what we'll do on sandbox violations
|
||||
if (~ipromises & (1ul << PROMISE_EXEC)) {
|
||||
// our sigsys error message handler can't be inherited across
|
||||
// execve() boundaries so if you've pledged exec then that'll
|
||||
// mean no error messages for you.
|
||||
switch (mode) {
|
||||
case kPledgeModeKillThread:
|
||||
sf[0].k = SECCOMP_RET_KILL_THREAD;
|
||||
break;
|
||||
case kPledgeModeKillProcess:
|
||||
sf[0].k = SECCOMP_RET_KILL_PROCESS;
|
||||
break;
|
||||
case kPledgeModeErrno:
|
||||
sf[0].k = SECCOMP_RET_ERRNO | Eperm;
|
||||
break;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
AppendFilter(&f, PLEDGE(sf));
|
||||
} else {
|
||||
if (mode & PLEDGE_STDERR_LOGGING) {
|
||||
// trapping mode
|
||||
//
|
||||
// if we haven't pledged exec, then we can monitor SIGSYS
|
||||
// and print a helpful error message when things do break
|
||||
// to avoid tls / static memory, we embed mode within bpf
|
||||
|
@ -1962,6 +1935,29 @@ privileged int sys_pledge_linux(unsigned long ipromises, //
|
|||
AllowMonitor(&f);
|
||||
sf[0].k = SECCOMP_RET_TRAP | (mode & SECCOMP_RET_DATA);
|
||||
AppendFilter(&f, PLEDGE(sf));
|
||||
} else {
|
||||
// non-trapping mode
|
||||
//
|
||||
// 1. our sigsys error message handler can't be inherited across
|
||||
// execve() boundaries so if you've pledged exec then that'll
|
||||
// mean no error messages for you.
|
||||
//
|
||||
// 2. we do not trap pledge("", 0) because that would go against
|
||||
// its documented purpose of only permitted exit().
|
||||
switch (mode & PLEDGE_PENALTY_MASK) {
|
||||
case PLEDGE_PENALTY_KILL_THREAD:
|
||||
sf[0].k = SECCOMP_RET_KILL_THREAD;
|
||||
break;
|
||||
case PLEDGE_PENALTY_KILL_PROCESS:
|
||||
sf[0].k = SECCOMP_RET_KILL_PROCESS;
|
||||
break;
|
||||
case PLEDGE_PENALTY_RETURN_EPERM:
|
||||
sf[0].k = SECCOMP_RET_ERRNO | Eperm;
|
||||
break;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
AppendFilter(&f, PLEDGE(sf));
|
||||
}
|
||||
|
||||
// drop privileges
|
||||
|
|
|
@ -44,23 +44,8 @@
|
|||
* an error, because the specified operations will be permitted.
|
||||
*
|
||||
* The promises you give pledge() define which system calls are allowed.
|
||||
* Error messages are logged when sandbox violations occur that well you
|
||||
* which promise was needed, to stderr on Linux and /var/log/messages on
|
||||
* OpenBSD, and the unwatchable termination signal should be SIGABRT.
|
||||
*
|
||||
* Standard error logging can't happen on Linux if you use the `exec`
|
||||
* promise, since we polyfill logging in userspace which can't cross
|
||||
* execve() boundaries. However once you pledge away `exec` it works.
|
||||
* Another inconsistency that pledging `exec` causes, is your process
|
||||
* termination signal may become SIGSYS rather than SIGABRT.
|
||||
*
|
||||
* On Linux, our SECCOMP BPF polyfill offers more configurability in
|
||||
* terms of behavior. It's possible to choose different behaviors that
|
||||
* determine how sandbox violations are handled.
|
||||
*
|
||||
* __pledge_mode = kPledgeModeKillThread; // kill thread [default]
|
||||
* __pledge_mode = kPledgeModeKillProcess; // kill all threads
|
||||
* __pledge_mode = kPledgeModeErrno; // just return EPERM
|
||||
* Error messages are logged when sandbox violations occur, but how that
|
||||
* happens depends on the `mode` parameter (see below).
|
||||
*
|
||||
* Timing is everything with pledge. It's designed to be a voluntary
|
||||
* self-imposed security model. That works best when programs perform
|
||||
|
@ -91,13 +76,6 @@
|
|||
* User and group IDs can't be changed once pledge is in effect. OpenBSD
|
||||
* should ignore chown without crashing; whereas Linux will just EPERM.
|
||||
*
|
||||
* Memory functions won't permit creating executable code after pledge.
|
||||
* Restrictions on origin of SYSCALL instructions will become enforced
|
||||
* on Linux (cf. msyscall) after pledge too, which means the process
|
||||
* gets killed if SYSCALL is used outside the .privileged section. One
|
||||
* exception is if the "exec" group is specified, in which case these
|
||||
* restrictions need to be loosened.
|
||||
*
|
||||
* Using pledge is irreversible. On Linux it causes PR_SET_NO_NEW_PRIVS
|
||||
* to be set on your process; however, if "id" or "recvfd" are allowed
|
||||
* then then they theoretically could permit the gaining of some new
|
||||
|
@ -177,16 +155,13 @@
|
|||
*
|
||||
* - "settime" allows settimeofday and clock_adjtime.
|
||||
*
|
||||
* - "exec" allows execve, execveat. On Linux, using this promise will
|
||||
* cause (1) system call origin verification to be disabled; (2) error
|
||||
* logging will be disabled; and (3) your termination signals might
|
||||
* become SIGSYS instead of SIGABRT. Another thing to note is that
|
||||
* `exec` alone might not be enough by itself to let your executable
|
||||
* be executed. For dynamic, interpreted, and ape binaries, you'll
|
||||
* usually want `rpath` and `prot_exec` too. With APE it's possible to
|
||||
* work around this requirement, by "assimilating" your binaries
|
||||
* beforehand. See the assimilate.com program and `--assimilate` flag
|
||||
* which can be used to turn APE binaries into static native binaries.
|
||||
* - "exec" allows execve, execveat. Note that `exec` alone might not be
|
||||
* enough by itself to let your executable be executed. For dynamic,
|
||||
* interpreted, and ape binaries, you'll usually want `rpath` and
|
||||
* `prot_exec` too. With APE it's possible to work around this
|
||||
* requirement, by "assimilating" your binaries beforehand. See the
|
||||
* assimilate.com program and `--assimilate` flag which can be used to
|
||||
* turn APE binaries into static native binaries.
|
||||
*
|
||||
* - "prot_exec" allows mmap(PROT_EXEC) and mprotect(PROT_EXEC). This is
|
||||
* needed to (1) code morph mutexes in __enable_threads(), and it's
|
||||
|
@ -218,6 +193,41 @@
|
|||
* has to do this before calling sys_execve(), the executed process will
|
||||
* be weakened to have execute permissions too.
|
||||
*
|
||||
* `__pledge_mode` is available to improve the experience of pledge() on
|
||||
* Linux. It should specify one of the following penalties:
|
||||
*
|
||||
* - `PLEDGE_PENALTY_KILL_THREAD` causes the violating thread to be
|
||||
* killed. This is the default on Linux. It's effectively the same as
|
||||
* killing the process, since redbean has no threads. The termination
|
||||
* signal can't be caught and will be either `SIGSYS` or `SIGABRT`.
|
||||
* Consider enabling stderr logging below so you'll know why your
|
||||
* program failed. Otherwise check the system log.
|
||||
*
|
||||
* - `PLEDGE_PENALTY_KILL_PROCESS` causes the process and all its
|
||||
* threads to be killed. This is always the case on OpenBSD.
|
||||
*
|
||||
* - `PLEDGE_PENALTY_RETURN_EPERM` causes system calls to just return an
|
||||
* `EPERM` error instead of killing. This is a gentler solution that
|
||||
* allows code to display a friendly warning. Please note this may
|
||||
* lead to weird behaviors if the software being sandboxed is lazy
|
||||
* about checking error results.
|
||||
*
|
||||
* `mode` may optionally bitwise or the following flags:
|
||||
*
|
||||
* - `PLEDGE_STDERR_LOGGING` enables friendly error message logging
|
||||
* letting you know which promises are needed whenever violations
|
||||
* occur. Without this, violations will be logged to `dmesg` on Linux
|
||||
* if the penalty is to kill the process. You would then need to
|
||||
* manually look up the system call number and then cross reference it
|
||||
* with the cosmopolitan libc pledge() documentation. You can also use
|
||||
* `strace -ff` which is easier. This is ignored OpenBSD, which
|
||||
* already has a good system log. Turning on stderr logging (which
|
||||
* uses SECCOMP trapping) also means that the `WTERMSIG()` on your
|
||||
* killed processes will always be `SIGABRT` on both Linux and
|
||||
* OpenBSD. Otherwise, Linux prefers to raise `SIGSYS`. Enabling this
|
||||
* option might not be a good idea if you're pledging `exec` because
|
||||
* subprocesses can't inherit the `SIGSYS` handler this installs.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `execpromises` on Linux isn't a subset of `promises`
|
||||
* @raise EINVAL if `promises` allows exec and `execpromises` is null
|
||||
|
@ -240,7 +250,7 @@ int pledge(const char *promises, const char *execpromises) {
|
|||
STRACE("execpromises must be a subset of promises");
|
||||
rc = einval();
|
||||
} else {
|
||||
rc = sys_pledge_linux(ipromises, __pledge_mode, true);
|
||||
rc = sys_pledge_linux(ipromises, __pledge_mode);
|
||||
if (rc > -4096u) errno = -rc, rc = -1;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_
|
||||
|
||||
#define PLEDGE_PENALTY_KILL_THREAD 0x0000
|
||||
#define PLEDGE_PENALTY_KILL_PROCESS 0x0001
|
||||
#define PLEDGE_PENALTY_RETURN_EPERM 0x0002
|
||||
#define PLEDGE_PENALTY_MASK 0x000f
|
||||
#define PLEDGE_STDERR_LOGGING 0x0010
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
enum PledgeMode {
|
||||
kPledgeModeKillThread,
|
||||
kPledgeModeKillProcess,
|
||||
kPledgeModeErrno,
|
||||
};
|
||||
|
||||
extern enum PledgeMode __pledge_mode;
|
||||
extern int __pledge_mode;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -13,7 +13,7 @@ struct Pledges {
|
|||
|
||||
hidden extern const struct Pledges kPledge[PROMISE_LEN_];
|
||||
|
||||
int sys_pledge_linux(unsigned long, enum PledgeMode, bool) hidden;
|
||||
int sys_pledge_linux(unsigned long, int) hidden;
|
||||
int ParsePromises(const char *, unsigned long *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
|
||||
// XXX: should be inherited thread local
|
||||
// see also sys_pledge_linux() which is 100% pure
|
||||
enum PledgeMode __pledge_mode;
|
||||
int __pledge_mode;
|
||||
unsigned long __promises;
|
||||
unsigned long __execpromises;
|
||||
|
|
|
@ -61,7 +61,7 @@ void SetUp(void) {
|
|||
TEST(pledge, testSoftError) {
|
||||
if (IsOpenbsd()) return;
|
||||
SPAWN(fork);
|
||||
__pledge_mode = kPledgeModeErrno;
|
||||
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM;
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
_Exit(7);
|
||||
|
@ -70,7 +70,7 @@ TEST(pledge, testSoftError) {
|
|||
|
||||
TEST(pledge, testKillThreadMode) {
|
||||
SPAWN(fork);
|
||||
__pledge_mode = kPledgeModeKillThread;
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_THREAD | PLEDGE_STDERR_LOGGING;
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TERMS(SIGABRT);
|
||||
|
@ -78,7 +78,7 @@ TEST(pledge, testKillThreadMode) {
|
|||
|
||||
TEST(pledge, testKillProcessMode) {
|
||||
SPAWN(fork);
|
||||
__pledge_mode = kPledgeModeKillProcess;
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_PROCESS | PLEDGE_STDERR_LOGGING;
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TERMS(SIGABRT);
|
||||
|
@ -90,7 +90,7 @@ TEST(pledge, testLogMessage_inSoftyMode) {
|
|||
char msg[256] = {0};
|
||||
ASSERT_SYS(0, 0, pipe(fds));
|
||||
SPAWN(fork);
|
||||
__pledge_mode = kPledgeModeErrno;
|
||||
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM | PLEDGE_STDERR_LOGGING;
|
||||
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
|
@ -108,7 +108,7 @@ TEST(pledge, testLogMessage_onKillProcess) {
|
|||
char msg[256] = {0};
|
||||
ASSERT_SYS(0, 0, pipe(fds));
|
||||
SPAWN(fork);
|
||||
__pledge_mode = kPledgeModeKillThread;
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_THREAD | PLEDGE_STDERR_LOGGING;
|
||||
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
@ -121,25 +121,18 @@ TEST(pledge, testLogMessage_onKillProcess) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(pledge, testNoLogOrAbrtsignoPossibleSadly_becausePledgedExec) {
|
||||
int fds[2];
|
||||
char msg[256] = {0};
|
||||
ASSERT_SYS(0, 0, pipe(fds));
|
||||
SPAWN(fork);
|
||||
ASSERT_SYS(0, 2, dup2(fds[1], 2));
|
||||
ASSERT_SYS(0, 0, pledge("stdio exec", "stdio exec"));
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TERMS(IsOpenbsd() ? SIGABRT : SIGSYS);
|
||||
close(fds[1]);
|
||||
read(fds[0], msg, sizeof(msg));
|
||||
close(fds[0]);
|
||||
ASSERT_STREQ("", msg);
|
||||
}
|
||||
|
||||
TEST(pledge, testDoublePledge_isFine) {
|
||||
SPAWN(fork);
|
||||
__pledge_mode = kPledgeModeKillThread;
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_THREAD;
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
EXITS(0);
|
||||
}
|
||||
|
||||
TEST(pledge, testEmptyPledge_doesntUseTrapping) {
|
||||
SPAWN(fork);
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_PROCESS;
|
||||
ASSERT_SYS(0, 0, pledge("", 0));
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TERMS(IsOpenbsd() ? SIGABRT : SIGSYS);
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ void SetUp(void) {
|
|||
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/sock.elf", "sock.elf", 0755));
|
||||
__pledge_mode = kPledgeModeErrno;
|
||||
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM;
|
||||
}
|
||||
|
||||
TEST(pledge, default_allowsExit) {
|
||||
|
@ -116,7 +116,7 @@ TEST(pledge, execpromises_notok) {
|
|||
int ws, pid;
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
__pledge_mode = kPledgeModeErrno;
|
||||
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM;
|
||||
ASSERT_SYS(0, 0, pledge("stdio rpath exec", "stdio"));
|
||||
execl("sock.elf", "sock.elf", 0);
|
||||
_Exit(127);
|
||||
|
@ -158,7 +158,7 @@ TEST(pledge, stdio_forbidsOpeningPasswd1) {
|
|||
|
||||
TEST(pledge, stdio_forbidsOpeningPasswd2) {
|
||||
int ws, pid;
|
||||
__pledge_mode = kPledgeModeKillProcess;
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_PROCESS;
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
|
|
|
@ -375,7 +375,7 @@ TEST(unveil, usedTwice_forbidden_worksWithPledge) {
|
|||
ASSERT_NE(-1, wait(&ws));
|
||||
ASSERT_TRUE(*gotsome);
|
||||
ASSERT_TRUE(WIFSIGNALED(ws));
|
||||
ASSERT_EQ(SIGABRT, WTERMSIG(ws));
|
||||
ASSERT_EQ(IsOpenbsd() ? SIGABRT : SIGSYS, WTERMSIG(ws));
|
||||
EXPECT_SYS(0, 0, munmap(gotsome, FRAMESIZE));
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
assert(assert(argon2.hash_encoded("password", "somesalt", {
|
||||
variant = argon2.variants.argon2_i,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge('stdio')
|
||||
assert(unix.pledge('stdio'))
|
||||
|
||||
local function test(s, b64)
|
||||
assert(EncodeBase64(s) == b64)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
assert(EncodeJson(nil) == "null")
|
||||
assert(EncodeJson(true) == "true")
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
assert(EncodeLua(nil) == "nil")
|
||||
assert(EncodeLua(true) == "true")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- https://www.json.org/JSON_checker/test.zip
|
||||
-- JSON parsing sample test case: fail11.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- https://www.json.org/JSON_checker/test.zip
|
||||
-- JSON parsing sample test case: pass1.json
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- these test cases are prefixed with n_
|
||||
-- ljson should reject all of them as invalid
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- these test cases are prefixed with n_
|
||||
-- ljson should reject all of them as invalid
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- these test cases are prefixed with n_
|
||||
-- ljson should reject all of them as invalid
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- these test cases are prefixed with n_
|
||||
-- ljson should reject all of them as invalid
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- these test cases are prefixed with i_
|
||||
-- ljson is free to accept or reject,
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- these test cases are prefixed with y_
|
||||
-- ljson should accept all of them as valid
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
x = Rdtsc()
|
||||
y = Rdtsc()
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
assert(EncodeLua(assert(DecodeJson[[ 0 ]])) == '0' )
|
||||
assert(EncodeLua(assert(DecodeJson[[ [1] ]])) == '{1}')
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
assert(string.match("127.123.231.1", "%d+.%d+.%d+.%d+"))
|
||||
assert(re.search([[^\d{1,3}(\.\d{1,3}){3}$]], "127.123.231.1"))
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
-- test redbean lua language extensions
|
||||
assert(0b100 == 4)
|
||||
|
|
|
@ -59,7 +59,7 @@ function UnixTest()
|
|||
-- fork
|
||||
-- basic subprocess creation
|
||||
if assert(unix.fork()) == 0 then
|
||||
unix.pledge("")
|
||||
assert(unix.pledge(""))
|
||||
unix.exit(42)
|
||||
end
|
||||
pid, ws = assert(unix.wait())
|
||||
|
@ -82,7 +82,7 @@ function UnixTest()
|
|||
unix.close(reader)
|
||||
pid, ws = assert(unix.wait())
|
||||
assert(unix.WIFSIGNALED(ws))
|
||||
assert(unix.WTERMSIG(ws) == unix.SIGABRT)
|
||||
assert(unix.WTERMSIG(ws) == unix.SIGSYS)
|
||||
elseif GetHostOs() == "OPENBSD" then
|
||||
if assert(unix.fork()) == 0 then
|
||||
assert(unix.pledge("stdio"))
|
||||
|
@ -160,7 +160,7 @@ function main()
|
|||
assert(unix.makedirs(tmpdir))
|
||||
unix.unveil(tmpdir, "rwc")
|
||||
unix.unveil(nil, nil)
|
||||
unix.pledge("stdio rpath wpath cpath proc")
|
||||
assert(unix.pledge("stdio rpath wpath cpath proc"))
|
||||
ok, err = pcall(UnixTest)
|
||||
if ok then
|
||||
assert(unix.rmrf(tmpdir))
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge('stdio')
|
||||
assert(unix.pledge('stdio'))
|
||||
|
||||
assert(Md5(nil) == nil)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
unix.pledge("stdio")
|
||||
assert(unix.pledge("stdio"))
|
||||
|
||||
assert("/usr/lib" == path.dirname("/usr/lib/foo.bar"))
|
||||
assert("/usr" == path.dirname("/usr/lib"))
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
-- 5869). As with RFC 4634, code to perform SHA-based Hashed Message
|
||||
-- Authentication Codes (HMACs) is also included.
|
||||
|
||||
unix.pledge('stdio')
|
||||
assert(unix.pledge('stdio'))
|
||||
|
||||
-- SHA-1
|
||||
assert(Sha1(nil) == nil)
|
||||
|
|
|
@ -40,7 +40,7 @@ local function main()
|
|||
assert(unix.makedirs(tmpdir))
|
||||
unix.unveil(tmpdir, "rwc")
|
||||
unix.unveil(nil, nil)
|
||||
unix.pledge("stdio rpath wpath cpath")
|
||||
assert(unix.pledge("stdio rpath wpath cpath"))
|
||||
ok, err = pcall(SlurpTest)
|
||||
if ok then
|
||||
assert(unix.rmrf(tmpdir))
|
||||
|
|
10
third_party/lua/lunix.c
vendored
10
third_party/lua/lunix.c
vendored
|
@ -1377,12 +1377,12 @@ static int LuaUnixSiocgifconf(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// sandbox.pledge([promises:str[, execpromises:str]])
|
||||
// sandbox.pledge([promises:str[, execpromises:str[, mode:int]]])
|
||||
// ├─→ true
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixPledge(lua_State *L) {
|
||||
int olderr = errno;
|
||||
__pledge_mode = 0;
|
||||
__pledge_mode = luaL_optinteger(L, 3, 0);
|
||||
return SysretBool(L, "pledge", olderr,
|
||||
pledge(luaL_checkstring(L, 1), luaL_optstring(L, 2, 0)));
|
||||
}
|
||||
|
@ -2829,5 +2829,11 @@ int LuaUnix(lua_State *L) {
|
|||
LuaSetIntField(L, "PATH_MAX", _PATH_MAX);
|
||||
LuaSetIntField(L, "PIPE_BUF", PIPE_BUF);
|
||||
|
||||
// pledge() flags
|
||||
LuaSetIntField(L, "PLEDGE_PENALTY_KILL_THREAD", PLEDGE_PENALTY_KILL_THREAD);
|
||||
LuaSetIntField(L, "PLEDGE_PENALTY_KILL_PROCESS", PLEDGE_PENALTY_KILL_PROCESS);
|
||||
LuaSetIntField(L, "PLEDGE_PENALTY_RETURN_EPERM", PLEDGE_PENALTY_RETURN_EPERM);
|
||||
LuaSetIntField(L, "PLEDGE_STDERR_LOGGING", PLEDGE_STDERR_LOGGING);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
/*
|
||||
* runs pledge at glibc executable load time, e.g.
|
||||
* strace -vff bash -c '_PLEDGE=4194303,0,1 LD_PRELOAD=$HOME/sandbox.so ls'
|
||||
* strace -vff bash -c '_PLEDGE=4194303,0 LD_PRELOAD=$HOME/sandbox.so ls'
|
||||
*/
|
||||
|
||||
hidden uint8_t __privileged_start[1];
|
||||
|
@ -33,9 +33,9 @@ hidden uint8_t __privileged_end[1];
|
|||
__attribute__((__constructor__)) void init(void) {
|
||||
int c, i, j;
|
||||
const char *s;
|
||||
uint64_t arg[3] = {0};
|
||||
uint64_t arg[2] = {0};
|
||||
s = getenv("_PLEDGE");
|
||||
for (i = j = 0; i < 3; ++i) {
|
||||
for (i = j = 0; i < 2; ++i) {
|
||||
while ((c = s[j] & 255)) {
|
||||
++j;
|
||||
if ('0' <= c & c <= '9') {
|
||||
|
@ -46,5 +46,5 @@ __attribute__((__constructor__)) void init(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
sys_pledge_linux(~arg[0], arg[1], arg[2]);
|
||||
sys_pledge_linux(~arg[0], arg[1]);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ usage: pledge.com [-hnN] PROG ARGS...\n\
|
|||
-c PATH call chroot()\n\
|
||||
-v [PERM:]PATH call unveil(PATH, PERM[rwxc])\n\
|
||||
-V disable unveiling (only pledge)\n\
|
||||
-q disable stderr violation logging\n\
|
||||
-k kill process rather than eperm'ing\n\
|
||||
-n set maximum niceness\n\
|
||||
-D don't drop capabilities\n\
|
||||
|
@ -130,6 +131,7 @@ int g_uflag;
|
|||
int g_kflag;
|
||||
int g_hflag;
|
||||
bool g_nice;
|
||||
bool g_qflag;
|
||||
bool isdynamic;
|
||||
bool g_noclose;
|
||||
long g_cpuquota;
|
||||
|
@ -157,11 +159,14 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
g_proquota = GetCpuCount() * 100;
|
||||
g_memquota = 4L * 1024 * 1024 * 1024;
|
||||
if (!sysinfo(&si)) g_memquota = si.totalram;
|
||||
while ((opt = getopt(argc, argv, "hnkNVT:p:u:g:c:C:D:P:M:F:v:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hnqkNVT:p:u:g:c:C:D:P:M:F:v:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
g_nice = true;
|
||||
break;
|
||||
case 'q':
|
||||
g_qflag = true;
|
||||
break;
|
||||
case 'k':
|
||||
g_kflag = true;
|
||||
break;
|
||||
|
@ -758,15 +763,18 @@ int main(int argc, char *argv[]) {
|
|||
// crash messages if we're not pledging exec, which is what this tool
|
||||
// always has to do currently.
|
||||
if (g_kflag) {
|
||||
__pledge_mode = kPledgeModeKillProcess;
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_PROCESS;
|
||||
} else {
|
||||
__pledge_mode = kPledgeModeErrno;
|
||||
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM;
|
||||
}
|
||||
|
||||
// we need to be able to call execv and mmap the dso
|
||||
// it'll be pledged away once/if the dso gets loaded
|
||||
if (!(~ipromises & (1ul << PROMISE_EXEC))) {
|
||||
g_promises = xstrcat(g_promises, ' ', "exec");
|
||||
if (!g_qflag) {
|
||||
__pledge_mode |= PLEDGE_STDERR_LOGGING;
|
||||
}
|
||||
}
|
||||
if (isdynamic) {
|
||||
g_promises = xstrcat(g_promises, ' ', "prot_exec");
|
||||
|
@ -774,8 +782,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
// pass arguments to pledge() inside the dso
|
||||
if (isdynamic) {
|
||||
ksnprintf(buf, sizeof(buf), "_PLEDGE=%ld,%ld,%ld", ~ipromises,
|
||||
__pledge_mode, false);
|
||||
ksnprintf(buf, sizeof(buf), "_PLEDGE=%ld,%ld", ~ipromises, __pledge_mode);
|
||||
putenv(buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -3832,7 +3832,7 @@ UNIX MODULE
|
|||
|
||||
See the unix.Rusage section below for details on returned fields.
|
||||
|
||||
unix.pledge([promises:str[, execpromises:str]])
|
||||
unix.pledge([promises:str[, execpromises:str[, mode:int]]])
|
||||
├─→ true
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
|
@ -3862,13 +3862,6 @@ UNIX MODULE
|
|||
OpenBSD should ignore the chown functions without crashing. Linux
|
||||
will just EPERM.
|
||||
|
||||
Memory functions won't permit creating executable code after pledge.
|
||||
Restrictions on origin of SYSCALL instructions will become enforced
|
||||
on Linux (cf. msyscall) after pledge too, which means the process
|
||||
gets killed if SYSCALL is used outside the .privileged section. One
|
||||
exception is if the "exec" group is specified, in which case these
|
||||
restrictions need to be loosened.
|
||||
|
||||
`promises` is a string that may include any of the following groups
|
||||
delimited by spaces. This list has been curated to focus on the
|
||||
system calls for which this module provides wrappers. See the
|
||||
|
@ -3985,6 +3978,39 @@ UNIX MODULE
|
|||
Since Linux has to do this before calling sys_execve(), the executed
|
||||
process will be weakened to have execute permissions too.
|
||||
|
||||
`mode` if specified should specify one penalty:
|
||||
|
||||
- `unix.PLEDGE_PENALTY_KILL_THREAD` causes the violating thread to
|
||||
be killed. This is the default on Linux. It's effectively the
|
||||
same as killing the process, since redbean has no threads. The
|
||||
termination signal can't be caught and will be either `SIGSYS`
|
||||
or `SIGABRT`. Consider enabling stderr logging below so you'll
|
||||
know why your program failed. Otherwise check the system log.
|
||||
|
||||
- `unix.PLEDGE_PENALTY_KILL_PROCESS` causes the process and all
|
||||
its threads to be killed. This is always the case on OpenBSD.
|
||||
|
||||
- `unix.PLEDGE_PENALTY_RETURN_EPERM` causes system calls to just
|
||||
return an `EPERM` error instead of killing. This is a gentler
|
||||
solution that allows code to display a friendly warning. Please
|
||||
note this may lead to weird behaviors if the software being
|
||||
sandboxed is lazy about checking error results.
|
||||
|
||||
`mode` may optionally bitwise or the following flags:
|
||||
|
||||
- `unix.PLEDGE_STDERR_LOGGING` enables friendly error message
|
||||
logging letting you know which promises are needed whenever
|
||||
violations occur. Without this, violations will be logged to
|
||||
`dmesg` on Linux if the penalty is to kill the process. You
|
||||
would then need to manually look up the system call number and
|
||||
then cross reference it with the cosmopolitan libc pledge()
|
||||
documentation. You can also use `strace -ff` which is easier.
|
||||
This is ignored OpenBSD, which already has a good system log.
|
||||
Turning on stderr logging (which uses SECCOMP trapping) also
|
||||
means that the `unix.WTERMSIG()` on your killed processes will
|
||||
always be `unix.SIGABRT` on both Linux and OpenBSD. Otherwise,
|
||||
Linux prefers to raise `unix.SIGSYS`.
|
||||
|
||||
unix.unveil(path:str, permissions:str)
|
||||
├─→ true
|
||||
└─→ nil, unix.Errno
|
||||
|
|
|
@ -6588,7 +6588,7 @@ static void UnveilRedbean(void) {
|
|||
}
|
||||
|
||||
static int EnableSandbox(void) {
|
||||
__pledge_mode = kPledgeModeErrno;
|
||||
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM | PLEDGE_STDERR_LOGGING;
|
||||
switch (sandboxed) {
|
||||
case 0:
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue