mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Add pledge.com for launching commands in a sandbox
This commit is contained in:
parent
12d9f7ade6
commit
1d490fcb94
8 changed files with 308 additions and 297 deletions
|
@ -99,6 +99,15 @@ if [ x"$(uname -s)" = xLinux ]; then
|
||||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||||
echo done >&2
|
echo done >&2
|
||||||
|
|
||||||
|
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||||
|
echo >&2
|
||||||
|
echo enabling binfmt_misc >&2
|
||||||
|
echo you may need to edit configs to persist across reboot >&2
|
||||||
|
echo $SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' >&2
|
||||||
|
$SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' || exit
|
||||||
|
echo done >&2
|
||||||
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
|
@ -42,12 +42,13 @@
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#define READONLY 0x8000
|
#define READONLY 0x8000
|
||||||
#define INET 0x8000
|
#define WRITEONLY 0x4000
|
||||||
#define UNIX 0x4000
|
#define INET 0x8000
|
||||||
#define ADDRLESS 0x2000
|
#define UNIX 0x4000
|
||||||
#define LOCK 0x8000
|
#define ADDRLESS 0x2000
|
||||||
#define TTY 0x8000
|
#define LOCK 0x8000
|
||||||
|
#define TTY 0x8000
|
||||||
|
|
||||||
#define OFF(f) offsetof(struct seccomp_data, f)
|
#define OFF(f) offsetof(struct seccomp_data, f)
|
||||||
#define PLEDGE(pledge) pledge, ARRAYLEN(pledge)
|
#define PLEDGE(pledge) pledge, ARRAYLEN(pledge)
|
||||||
|
@ -157,25 +158,29 @@ static const uint16_t kPledgeLinuxRpath[] = {
|
||||||
__NR_linux_faccessat, //
|
__NR_linux_faccessat, //
|
||||||
__NR_linux_readlink, //
|
__NR_linux_readlink, //
|
||||||
__NR_linux_readlinkat, //
|
__NR_linux_readlinkat, //
|
||||||
|
__NR_linux_statfs, //
|
||||||
|
__NR_linux_fstatfs, //
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t kPledgeLinuxWpath[] = {
|
static const uint16_t kPledgeLinuxWpath[] = {
|
||||||
__NR_linux_getcwd, //
|
__NR_linux_getcwd, //
|
||||||
__NR_linux_open, //
|
__NR_linux_open | WRITEONLY, //
|
||||||
__NR_linux_openat, //
|
__NR_linux_openat | WRITEONLY, //
|
||||||
__NR_linux_stat, //
|
__NR_linux_stat, //
|
||||||
__NR_linux_fstat, //
|
__NR_linux_fstat, //
|
||||||
__NR_linux_lstat, //
|
__NR_linux_lstat, //
|
||||||
__NR_linux_fstatat, //
|
__NR_linux_fstatat, //
|
||||||
__NR_linux_access, //
|
__NR_linux_access, //
|
||||||
__NR_linux_faccessat, //
|
__NR_linux_faccessat, //
|
||||||
__NR_linux_readlinkat, //
|
__NR_linux_readlinkat, //
|
||||||
__NR_linux_chmod, //
|
__NR_linux_chmod, //
|
||||||
__NR_linux_fchmod, //
|
__NR_linux_fchmod, //
|
||||||
__NR_linux_fchmodat, //
|
__NR_linux_fchmodat, //
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t kPledgeLinuxCpath[] = {
|
static const uint16_t kPledgeLinuxCpath[] = {
|
||||||
|
__NR_linux_open, //
|
||||||
|
__NR_linux_openat, //
|
||||||
__NR_linux_rename, //
|
__NR_linux_rename, //
|
||||||
__NR_linux_renameat, //
|
__NR_linux_renameat, //
|
||||||
__NR_linux_renameat2, //
|
__NR_linux_renameat2, //
|
||||||
|
@ -278,9 +283,20 @@ static const uint16_t kPledgeLinuxId[] = {
|
||||||
__NR_linux_setrlimit, //
|
__NR_linux_setrlimit, //
|
||||||
__NR_linux_getpriority, //
|
__NR_linux_getpriority, //
|
||||||
__NR_linux_setpriority, //
|
__NR_linux_setpriority, //
|
||||||
|
__NR_linux_setfsuid, //
|
||||||
|
__NR_linux_setfsgid, //
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t kPledgeLinuxExec[] = {
|
static const uint16_t kPledgeLinuxExec[] = {
|
||||||
|
__NR_linux_execve, //
|
||||||
|
__NR_linux_execveat, //
|
||||||
|
__NR_linux_access, //
|
||||||
|
__NR_linux_faccessat, //
|
||||||
|
__NR_linux_open | READONLY, //
|
||||||
|
__NR_linux_openat | READONLY, //
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint16_t kPledgeLinuxExecnative[] = {
|
||||||
__NR_linux_execve, //
|
__NR_linux_execve, //
|
||||||
__NR_linux_execveat, //
|
__NR_linux_execveat, //
|
||||||
};
|
};
|
||||||
|
@ -290,24 +306,25 @@ static const struct Pledges {
|
||||||
const uint16_t *syscalls;
|
const uint16_t *syscalls;
|
||||||
const size_t len;
|
const size_t len;
|
||||||
} kPledgeLinux[] = {
|
} kPledgeLinux[] = {
|
||||||
{"default", PLEDGE(kPledgeLinuxDefault)}, //
|
{"default", PLEDGE(kPledgeLinuxDefault)}, //
|
||||||
{"stdio", PLEDGE(kPledgeLinuxStdio)}, //
|
{"stdio", PLEDGE(kPledgeLinuxStdio)}, //
|
||||||
{"rpath", PLEDGE(kPledgeLinuxRpath)}, //
|
{"rpath", PLEDGE(kPledgeLinuxRpath)}, //
|
||||||
{"wpath", PLEDGE(kPledgeLinuxWpath)}, //
|
{"wpath", PLEDGE(kPledgeLinuxWpath)}, //
|
||||||
{"cpath", PLEDGE(kPledgeLinuxCpath)}, //
|
{"cpath", PLEDGE(kPledgeLinuxCpath)}, //
|
||||||
{"dpath", PLEDGE(kPledgeLinuxDpath)}, //
|
{"dpath", PLEDGE(kPledgeLinuxDpath)}, //
|
||||||
{"flock", PLEDGE(kPledgeLinuxFlock)}, //
|
{"flock", PLEDGE(kPledgeLinuxFlock)}, //
|
||||||
{"fattr", PLEDGE(kPledgeLinuxFattr)}, //
|
{"fattr", PLEDGE(kPledgeLinuxFattr)}, //
|
||||||
{"inet", PLEDGE(kPledgeLinuxInet)}, //
|
{"inet", PLEDGE(kPledgeLinuxInet)}, //
|
||||||
{"unix", PLEDGE(kPledgeLinuxUnix)}, //
|
{"unix", PLEDGE(kPledgeLinuxUnix)}, //
|
||||||
{"dns", PLEDGE(kPledgeLinuxDns)}, //
|
{"dns", PLEDGE(kPledgeLinuxDns)}, //
|
||||||
{"tty", PLEDGE(kPledgeLinuxTty)}, //
|
{"tty", PLEDGE(kPledgeLinuxTty)}, //
|
||||||
{"recvfd", PLEDGE(kPledgeLinuxRecvfd)}, //
|
{"recvfd", PLEDGE(kPledgeLinuxRecvfd)}, //
|
||||||
{"proc", PLEDGE(kPledgeLinuxProc)}, //
|
{"proc", PLEDGE(kPledgeLinuxProc)}, //
|
||||||
{"thread", PLEDGE(kPledgeLinuxThread)}, //
|
{"thread", PLEDGE(kPledgeLinuxThread)}, //
|
||||||
{"exec", PLEDGE(kPledgeLinuxExec)}, //
|
{"exec", PLEDGE(kPledgeLinuxExec)}, //
|
||||||
{"id", PLEDGE(kPledgeLinuxId)}, //
|
{"execnative", PLEDGE(kPledgeLinuxExecnative)}, //
|
||||||
{0}, //
|
{"id", PLEDGE(kPledgeLinuxId)}, //
|
||||||
|
{0}, //
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sock_filter kFilterStart[] = {
|
static const struct sock_filter kFilterStart[] = {
|
||||||
|
@ -397,23 +414,25 @@ static bool AllowIoctl(struct Filter *f) {
|
||||||
// - TIOCGPGRP (0x540f)
|
// - TIOCGPGRP (0x540f)
|
||||||
// - TIOCSWINSZ (0x5414)
|
// - TIOCSWINSZ (0x5414)
|
||||||
// - TIOCSBRK (0x5427)
|
// - TIOCSBRK (0x5427)
|
||||||
|
// - TCFLSH (0x540b)
|
||||||
//
|
//
|
||||||
static bool AllowIoctlTty(struct Filter *f) {
|
static bool AllowIoctlTty(struct Filter *f) {
|
||||||
static const struct sock_filter fragment[] = {
|
static const struct sock_filter fragment[] = {
|
||||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 13 - 1),
|
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 14 - 1),
|
||||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||||
/* L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5401, 11 - 3, 0),
|
/* L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5401, 12 - 3, 0),
|
||||||
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5402, 11 - 4, 0),
|
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5402, 12 - 4, 0),
|
||||||
/* L4*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5403, 11 - 5, 0),
|
/* L4*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5403, 12 - 5, 0),
|
||||||
/* L5*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5404, 11 - 6, 0),
|
/* L5*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5404, 12 - 6, 0),
|
||||||
/* L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5413, 11 - 7, 0),
|
/* L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5413, 12 - 7, 0),
|
||||||
/* L7*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5410, 11 - 8, 0),
|
/* L7*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5410, 12 - 8, 0),
|
||||||
/* L8*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x540f, 11 - 9, 0),
|
/* L8*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x540f, 12 - 9, 0),
|
||||||
/* L9*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5414, 11 - 10, 0),
|
/* L9*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5414, 12 - 10, 0),
|
||||||
/*L10*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5427, 0, 12 - 11),
|
/*L10*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x540b, 12 - 11, 0),
|
||||||
/*L11*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
/*L11*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5427, 0, 13 - 12),
|
||||||
/*L12*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
/*L12*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||||
/*L13*/ /* next filter */
|
/*L13*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||||
|
/*L14*/ /* next filter */
|
||||||
};
|
};
|
||||||
return AppendFilter(f, PLEDGE(fragment));
|
return AppendFilter(f, PLEDGE(fragment));
|
||||||
}
|
}
|
||||||
|
@ -593,6 +612,42 @@ static bool AllowOpenatReadonly(struct Filter *f) {
|
||||||
return AppendFilter(f, PLEDGE(fragment));
|
return AppendFilter(f, PLEDGE(fragment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The open() flags parameter must not contain
|
||||||
|
//
|
||||||
|
// - O_CREAT (000000100)
|
||||||
|
// - O_TMPFILE (020200000)
|
||||||
|
//
|
||||||
|
static bool AllowOpenWriteonly(struct Filter *f) {
|
||||||
|
static const struct sock_filter fragment[] = {
|
||||||
|
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_open, 0, 6 - 1),
|
||||||
|
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||||
|
/*L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 020200100),
|
||||||
|
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 5 - 4),
|
||||||
|
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||||
|
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||||
|
/*L6*/ /* next filter */
|
||||||
|
};
|
||||||
|
return AppendFilter(f, PLEDGE(fragment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The openat() flags parameter must not contain
|
||||||
|
//
|
||||||
|
// - O_CREAT (000000100)
|
||||||
|
// - O_TMPFILE (020200000)
|
||||||
|
//
|
||||||
|
static bool AllowOpenatWriteonly(struct Filter *f) {
|
||||||
|
static const struct sock_filter fragment[] = {
|
||||||
|
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_openat, 0, 6 - 1),
|
||||||
|
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||||
|
/*L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 020200100),
|
||||||
|
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 5 - 4),
|
||||||
|
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||||
|
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||||
|
/*L6*/ /* next filter */
|
||||||
|
};
|
||||||
|
return AppendFilter(f, PLEDGE(fragment));
|
||||||
|
}
|
||||||
|
|
||||||
// If the flags parameter of open() has one of:
|
// If the flags parameter of open() has one of:
|
||||||
//
|
//
|
||||||
// - O_CREAT (000000100)
|
// - O_CREAT (000000100)
|
||||||
|
@ -810,23 +865,21 @@ static bool AllowSocketUnix(struct Filter *f) {
|
||||||
|
|
||||||
// The first parameter of prctl() can be any of
|
// The first parameter of prctl() can be any of
|
||||||
//
|
//
|
||||||
// - PR_SET_NO_NEW_PRIVS (38)
|
// - PR_SET_NAME (15)
|
||||||
|
// - PR_GET_NAME (16)
|
||||||
|
// - PR_GET_SECCOMP (21)
|
||||||
// - PR_SET_SECCOMP (22)
|
// - PR_SET_SECCOMP (22)
|
||||||
//
|
// - PR_SET_NO_NEW_PRIVS (38)
|
||||||
// The second parameter of prctl() can be any of
|
|
||||||
//
|
|
||||||
// - true (1)
|
|
||||||
// - SECCOMP_MODE_FILTER (2)
|
|
||||||
//
|
//
|
||||||
static bool AllowPrctl(struct Filter *f) {
|
static bool AllowPrctl(struct Filter *f) {
|
||||||
static const struct sock_filter fragment[] = {
|
static const struct sock_filter fragment[] = {
|
||||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_prctl, 0, 9 - 1),
|
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_prctl, 0, 9 - 1),
|
||||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||||
/*L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 38, 4 - 3, 0),
|
/*L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 15, 7 - 3, 0),
|
||||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 22, 0, 8 - 4),
|
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 16, 7 - 4, 0),
|
||||||
/*L4*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
/*L4*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 21, 7 - 5, 0),
|
||||||
/*L5*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 7 - 6, 0),
|
/*L5*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 22, 7 - 6, 0),
|
||||||
/*L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 2, 0, 8 - 7),
|
/*L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 38, 0, 8 - 7),
|
||||||
/*L7*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
/*L7*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||||
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||||
/*L9*/ /* next filter */
|
/*L9*/ /* next filter */
|
||||||
|
@ -937,6 +990,12 @@ static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len,
|
||||||
case __NR_linux_openat | READONLY:
|
case __NR_linux_openat | READONLY:
|
||||||
if (!AllowOpenatReadonly(f)) return false;
|
if (!AllowOpenatReadonly(f)) return false;
|
||||||
break;
|
break;
|
||||||
|
case __NR_linux_open | WRITEONLY:
|
||||||
|
if (!AllowOpenWriteonly(f)) return false;
|
||||||
|
break;
|
||||||
|
case __NR_linux_openat | WRITEONLY:
|
||||||
|
if (!AllowOpenatWriteonly(f)) return false;
|
||||||
|
break;
|
||||||
case __NR_linux_setsockopt:
|
case __NR_linux_setsockopt:
|
||||||
if (!AllowSetsockopt(f)) return false;
|
if (!AllowSetsockopt(f)) return false;
|
||||||
break;
|
break;
|
||||||
|
@ -990,6 +1049,7 @@ static int sys_pledge_linux(const char *promises, const char *execpromises) {
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
size_t plen;
|
size_t plen;
|
||||||
bool needmapexec;
|
bool needmapexec;
|
||||||
|
bool needexecnative;
|
||||||
bool needmorphing;
|
bool needmorphing;
|
||||||
struct Filter f = {0};
|
struct Filter f = {0};
|
||||||
const uint16_t *pledge;
|
const uint16_t *pledge;
|
||||||
|
@ -997,9 +1057,10 @@ static int sys_pledge_linux(const char *promises, const char *execpromises) {
|
||||||
if (execpromises) return einval();
|
if (execpromises) return einval();
|
||||||
needmapexec = strstr(promises, "exec");
|
needmapexec = strstr(promises, "exec");
|
||||||
needmorphing = strstr(promises, "thread");
|
needmorphing = strstr(promises, "thread");
|
||||||
|
needexecnative = strstr(promises, "execnative");
|
||||||
if ((start = s = strdup(promises)) &&
|
if ((start = s = strdup(promises)) &&
|
||||||
AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
|
AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
|
||||||
(needmapexec || AppendOriginVerification(&f)) &&
|
(needmapexec || needexecnative || AppendOriginVerification(&f)) &&
|
||||||
AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault),
|
AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault),
|
||||||
needmapexec, needmorphing)) {
|
needmapexec, needmorphing)) {
|
||||||
for (ok = true; (tok = strtok_r(start, " \t\r\n", &state)); start = 0) {
|
for (ok = true; (tok = strtok_r(start, " \t\r\n", &state)); start = 0) {
|
||||||
|
@ -1088,15 +1149,15 @@ static int sys_pledge_linux(const char *promises, const char *execpromises) {
|
||||||
*
|
*
|
||||||
* - "rpath" (read-only path ops) allows chdir, getcwd, open(O_RDONLY),
|
* - "rpath" (read-only path ops) allows chdir, getcwd, open(O_RDONLY),
|
||||||
* openat(O_RDONLY), stat, fstat, lstat, fstatat, access, faccessat,
|
* openat(O_RDONLY), stat, fstat, lstat, fstatat, access, faccessat,
|
||||||
* readlink, readlinkat.
|
* readlink, readlinkat, statfs, fstatfs.
|
||||||
*
|
*
|
||||||
* - "wpath" (write path ops) allows getcwd, open, openat, stat, fstat,
|
* - "wpath" (write path ops) allows getcwd, open(O_WRONLY),
|
||||||
* lstat, fstatat, access, faccessat, readlink, readlinkat, chmod,
|
* openat(O_WRONLY), stat, fstat, lstat, fstatat, access, faccessat,
|
||||||
* fchmod, fchmodat.
|
* readlink, readlinkat, chmod, fchmod, fchmodat.
|
||||||
*
|
*
|
||||||
* - "cpath" (create path ops) allows rename, renameat, renameat2, link,
|
* - "cpath" (create path ops) allows open(O_CREAT), openat(O_CREAT),
|
||||||
* linkat, symlink, symlinkat, unlink, rmdir, unlinkat, mkdir,
|
* rename, renameat, renameat2, link, linkat, symlink, symlinkat,
|
||||||
* mkdirat.
|
* unlink, rmdir, unlinkat, mkdir, mkdirat.
|
||||||
*
|
*
|
||||||
* - "dpath" (create special path ops) allows mknod, mknodat, mkfifo.
|
* - "dpath" (create special path ops) allows mknod, mknodat, mkfifo.
|
||||||
*
|
*
|
||||||
|
@ -1125,13 +1186,21 @@ static int sys_pledge_linux(const char *promises, const char *execpromises) {
|
||||||
* - "thread" allows clone, futex, and permits PROT_EXEC in mprotect.
|
* - "thread" allows clone, futex, and permits PROT_EXEC in mprotect.
|
||||||
*
|
*
|
||||||
* - "id" allows setuid, setreuid, setresuid, setgid, setregid,
|
* - "id" allows setuid, setreuid, setresuid, setgid, setregid,
|
||||||
* setresgid, setgroups, prlimit, setrlimit, getpriority, setpriority.
|
* setresgid, setgroups, prlimit, setrlimit, getpriority, setpriority,
|
||||||
|
* setfsuid, setfsgid.
|
||||||
*
|
*
|
||||||
* - "exec" allows execve, execveat. If this is used then APE binaries
|
* - "exec" allows execve, execveat, access, faccessat. On Linux this
|
||||||
* should be assimilated in order to work on OpenBSD. On Linux, mmap()
|
* also weakens some security to permit running APE binaries. However
|
||||||
|
* on OpenBSD they must be assimilate beforehand. On Linux, mmap()
|
||||||
* will be loosened up to allow creating PROT_EXEC memory (for APE
|
* will be loosened up to allow creating PROT_EXEC memory (for APE
|
||||||
* loader) and system call origin verification won't be activated.
|
* loader) and system call origin verification won't be activated.
|
||||||
*
|
*
|
||||||
|
* - "execnative" allows execve, execveat. Can only be used to run
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @raise ENOSYS if host os isn't Linux or OpenBSD
|
* @raise ENOSYS if host os isn't Linux or OpenBSD
|
||||||
* @raise EINVAL if `execpromises` is used on Linux
|
* @raise EINVAL if `execpromises` is used on Linux
|
||||||
|
|
|
@ -1536,7 +1536,6 @@ syscon termios EXTA 14 0x4b00 0x4b00 0x4b00 0x4b00 0 # bsd conse
|
||||||
syscon termios EXTB 15 0x9600 0x9600 0x9600 0x9600 0 # bsd consensus
|
syscon termios EXTB 15 0x9600 0x9600 0x9600 0x9600 0 # bsd consensus
|
||||||
syscon termios ERA 0x02002c 45 45 0 0 0
|
syscon termios ERA 0x02002c 45 45 0 0 0
|
||||||
syscon termios EMPTY 0 0 0 0 0 0 # consensus
|
syscon termios EMPTY 0 0 0 0 0 0 # consensus
|
||||||
syscon termios TCFLSH 0x540b 0 0 0 0 0
|
|
||||||
|
|
||||||
syscon termios TCFLSH 0x540b 0x80047410 0x80047410 0x80047410 0x80047410 0 # see tcflush; TIOCFLUSH on BSD
|
syscon termios TCFLSH 0x540b 0x80047410 0x80047410 0x80047410 0x80047410 0 # see tcflush; TIOCFLUSH on BSD
|
||||||
syscon termios TIOCFLUSH 0x540b 0x80047410 0x80047410 0x80047410 0x80047410 0 # see tcflush; TCFLSH on Linux
|
syscon termios TIOCFLUSH 0x540b 0x80047410 0x80047410 0x80047410 0x80047410 0 # see tcflush; TCFLSH on Linux
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#define PR_GET_NO_NEW_PRIVS 39
|
#define PR_GET_NO_NEW_PRIVS 39
|
||||||
|
|
||||||
#define PR_SET_NAME 15
|
#define PR_SET_NAME 15
|
||||||
#define PR_GET_NAME 0x10
|
#define PR_GET_NAME 16
|
||||||
|
|
||||||
#define PR_GET_TSC 25
|
#define PR_GET_TSC 25
|
||||||
#define PR_SET_TSC 26
|
#define PR_SET_TSC 26
|
||||||
|
|
|
@ -108,9 +108,9 @@ TEST(pledge, multipleCalls_canOnlyBecomeMoreRestrictive1) {
|
||||||
ASSERT_SYS(0, 0, pledge("stdio unix", 0));
|
ASSERT_SYS(0, 0, pledge("stdio unix", 0));
|
||||||
ASSERT_SYS(0, 3, dup(2));
|
ASSERT_SYS(0, 3, dup(2));
|
||||||
ASSERT_SYS(EPERM, -1, socket(AF_UNIX, SOCK_STREAM, 0));
|
ASSERT_SYS(EPERM, -1, socket(AF_UNIX, SOCK_STREAM, 0));
|
||||||
ASSERT_SYS(EPERM, -1, prctl(PR_SET_NO_NEW_PRIVS, 0, 0, 0, 0));
|
ASSERT_SYS(0, 2, prctl(PR_GET_SECCOMP, 0, 0));
|
||||||
ASSERT_SYS(EPERM, -1, prctl(PR_GET_SECCOMP, SECCOMP_MODE_FILTER, 0));
|
ASSERT_SYS(0, 0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
|
||||||
ASSERT_SYS(EPERM, -1, prctl(PR_SET_SECCOMP, 33, 0));
|
ASSERT_SYS(EINVAL, -1, prctl(PR_SET_NO_NEW_PRIVS, 0, 0, 0, 0));
|
||||||
_Exit(0);
|
_Exit(0);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, wait(&ws));
|
EXPECT_NE(-1, wait(&ws));
|
||||||
|
@ -347,8 +347,23 @@ TEST(pledge, open_wpath) {
|
||||||
ASSERT_SYS(0, 0, pledge("stdio wpath", 0));
|
ASSERT_SYS(0, 0, pledge("stdio wpath", 0));
|
||||||
ASSERT_SYS(0, 3, open("foo", O_RDONLY));
|
ASSERT_SYS(0, 3, open("foo", O_RDONLY));
|
||||||
ASSERT_SYS(EPERM, -1, open(".", O_RDWR | O_TMPFILE, 07644));
|
ASSERT_SYS(EPERM, -1, open(".", O_RDWR | O_TMPFILE, 07644));
|
||||||
ASSERT_SYS(EPERM, -1, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 07644));
|
ASSERT_SYS(0, 4, open("foo", O_WRONLY | O_TRUNC, 07644));
|
||||||
ASSERT_SYS(0, 4, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
ASSERT_SYS(EPERM, -1, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
EXPECT_NE(-1, wait(&ws));
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws) && !WEXITSTATUS(ws));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pledge, open_cpath) {
|
||||||
|
if (IsOpenbsd()) return; // b/c testing linux bpf
|
||||||
|
int ws, pid;
|
||||||
|
struct stat st;
|
||||||
|
ASSERT_SYS(0, 0, touch("foo", 0644));
|
||||||
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
|
if (!pid) {
|
||||||
|
ASSERT_SYS(0, 0, pledge("stdio cpath", 0));
|
||||||
|
ASSERT_SYS(0, 3, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
||||||
_Exit(0);
|
_Exit(0);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, wait(&ws));
|
EXPECT_NE(-1, wait(&ws));
|
||||||
|
|
|
@ -1,217 +0,0 @@
|
||||||
/*-*- 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/struct/filter.h"
|
|
||||||
#include "libc/calls/struct/sigaction.h"
|
|
||||||
#include "libc/calls/struct/siginfo.h"
|
|
||||||
#include "libc/calls/struct/sigset.h"
|
|
||||||
#include "libc/calls/struct/user_regs_struct.h"
|
|
||||||
#include "libc/calls/ucontext.h"
|
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/intrin/kprintf.h"
|
|
||||||
#include "libc/log/check.h"
|
|
||||||
#include "libc/log/log.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/sysv/consts/pr.h"
|
|
||||||
#include "libc/sysv/consts/ptrace.h"
|
|
||||||
#include "libc/sysv/consts/sa.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
|
||||||
#include "tool/net/sandbox.h"
|
|
||||||
|
|
||||||
#define __WALL 0x40000000
|
|
||||||
|
|
||||||
static const struct sock_filter kSandboxFilter[] = {
|
|
||||||
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
|
||||||
_SECCOMP_LOAD_SYSCALL_NR(), //
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x000), // read
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x001), // write
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x013), // readv
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x014), // writev
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x005), // fstat
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x007), // poll
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x010), // ioctl todo
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x016), // pipe
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x125), // pipe2
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x035), // socketpair
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x020), // dup
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x021), // dup2
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x124), // dup3
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x039), // fork
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x03a), // vfork
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x011), // pread
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x012), // pwrite
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x127), // preadv
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x128), // pwritev
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0d9), // getdents
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x028), // sendfile
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x02d), // recvfrom
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x033), // getsockname
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x034), // getpeername
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x082), // rt_sigsuspend
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x060), // gettimeofday
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x03c), // exit
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x03e, 0), // kill
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x101, 0), // openat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x106, 0), // newfstatat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x029, 0), // socket
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x031, 0), // bind
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x02a, 0), // connect
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x02c, 0), // sendto
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x036, 0), // setsockopt
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x048, 0), // fcntl
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x03b, 0), // execve
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x102, 0), // mkdirat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x104, 0), // chownat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x107, 0), // unlinkat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x108, 0), // renameat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x109, 0), // linkat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x10a, 0), // symlinkat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x10b, 0), // readlinkat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x10c, 0), // fchmodat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x10d, 0), // faccessat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x0eb, 0), // utimes
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x105, 0), // futimesat
|
|
||||||
_SECCOMP_TRACE_SYSCALL(0x118, 0), // utimensat
|
|
||||||
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct sock_fprog kSandbox = {
|
|
||||||
.len = ARRAYLEN(kSandboxFilter),
|
|
||||||
.filter = kSandboxFilter,
|
|
||||||
};
|
|
||||||
|
|
||||||
void OnSys(int sig, siginfo_t *si, ucontext_t *ctx) {
|
|
||||||
kprintf("Got SIGSYS%n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
sigset_t mask, origmask;
|
|
||||||
struct user_regs_struct regs;
|
|
||||||
int child, evpid, signal, wstatus;
|
|
||||||
|
|
||||||
if (!IsLinux()) {
|
|
||||||
kprintf("error: %s is only supported on linux right now%n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (argc < 2) {
|
|
||||||
kprintf("Usage: %s PROGRAM [ARGS...]%n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* ShowCrashReports(); */
|
|
||||||
|
|
||||||
sigaction(SIGINT, &(struct sigaction){.sa_handler = SIG_IGN}, 0);
|
|
||||||
sigaction(SIGQUIT, &(struct sigaction){.sa_handler = SIG_IGN}, 0);
|
|
||||||
sigaction(SIGSYS,
|
|
||||||
&((struct sigaction){
|
|
||||||
.sa_sigaction = OnSys,
|
|
||||||
.sa_flags = SA_SIGINFO,
|
|
||||||
}),
|
|
||||||
0);
|
|
||||||
|
|
||||||
sigemptyset(&mask);
|
|
||||||
sigaddset(&mask, SIGCHLD);
|
|
||||||
sigprocmask(SIG_BLOCK, &mask, &origmask);
|
|
||||||
|
|
||||||
CHECK_NE(-1, (child = fork()));
|
|
||||||
if (!child) {
|
|
||||||
sigaction(SIGINT, &(struct sigaction){.sa_handler = SIG_DFL}, 0);
|
|
||||||
sigaction(SIGQUIT, &(struct sigaction){.sa_handler = SIG_DFL}, 0);
|
|
||||||
kprintf("CHILD ptrace(PTRACE_TRACEME)%n");
|
|
||||||
if (ptrace(PTRACE_TRACEME) == -1) {
|
|
||||||
kprintf("CHILD ptrace(PTRACE_TRACEME) failed %m%n");
|
|
||||||
_Exit(124);
|
|
||||||
}
|
|
||||||
kprintf("CHILD prctl(PR_SET_NO_NEW_PRIVS)%n");
|
|
||||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
|
|
||||||
kprintf("CHILD prctl(PR_SET_NO_NEW_PRIVS) failed %m%n");
|
|
||||||
_Exit(125);
|
|
||||||
}
|
|
||||||
kprintf("CHILD prctl(PR_SET_SECCOMP)%n");
|
|
||||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &kSandbox) == -1) {
|
|
||||||
kprintf("CHILD prctl(PR_SET_SECCOMP) failed %m%n");
|
|
||||||
_Exit(126);
|
|
||||||
}
|
|
||||||
kprintf("CHILD sigsuspend()%n");
|
|
||||||
if (sigsuspend(0) == -1) {
|
|
||||||
kprintf("CHILD sigsuspend() failed %m%n");
|
|
||||||
}
|
|
||||||
sigaction(SIGSYS, &(struct sigaction){.sa_handler = SIG_DFL}, 0);
|
|
||||||
sigprocmask(SIG_SETMASK, &origmask, 0);
|
|
||||||
execv(argv[1], argv + 1);
|
|
||||||
kprintf("CHILD execve(%#s) failed %m%n", argv[1]);
|
|
||||||
_Exit(127);
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for ptrace(PTRACE_TRACEME) to be called
|
|
||||||
kprintf("PARENT waitpid(child, &wstatus)%n");
|
|
||||||
CHECK_EQ(child, waitpid(child, &wstatus, 0));
|
|
||||||
|
|
||||||
// configure linux process tracing
|
|
||||||
kprintf("PARENT ptrace(PTRACE_SETOPTIONS)%n");
|
|
||||||
CHECK_NE(-1, ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESECCOMP));
|
|
||||||
|
|
||||||
// continue child process
|
|
||||||
kprintf("PARENT ptrace(PTRACE_CONT)%n");
|
|
||||||
CHECK_NE(-1, ptrace(PTRACE_CONT, child, 0, 0));
|
|
||||||
|
|
||||||
kprintf("PARENT kill(child, SIGSYS)%n");
|
|
||||||
kill(child, SIGSYS);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
kprintf("PARENT waitpid()%n");
|
|
||||||
CHECK_NE(-1, (evpid = waitpid(-1, &wstatus, __WALL)));
|
|
||||||
if (WIFSTOPPED(wstatus)) {
|
|
||||||
signal = (wstatus >> 8) & 0xffff;
|
|
||||||
if (signal == SIGTRAP | PTRACE_EVENT_SECCOMP) {
|
|
||||||
// CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, evpid, 0, &msg));
|
|
||||||
CHECK_NE(-1, ptrace(PTRACE_GETREGS, evpid, 0, regs));
|
|
||||||
regs.rax = -EPERM;
|
|
||||||
CHECK_NE(-1, ptrace(PTRACE_GETREGS, evpid, 0, regs));
|
|
||||||
ptrace(PTRACE_CONT, evpid, 0, 0);
|
|
||||||
} else {
|
|
||||||
ptrace(PTRACE_CONT, evpid, 0, signal & 127);
|
|
||||||
}
|
|
||||||
} else if (WIFEXITED(wstatus)) {
|
|
||||||
exit(WEXITSTATUS(wstatus));
|
|
||||||
} else {
|
|
||||||
exit(128 + WTERMSIG(wstatus));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
136
tool/build/pledge.c
Normal file
136
tool/build/pledge.c
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*-*- 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/errno.h"
|
||||||
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "third_party/getopt/getopt.h"
|
||||||
|
|
||||||
|
// options used: hpugc
|
||||||
|
// letters not used: ABCDEFGHIJKLMNOPQRSTUVWXYZabdefijklmnoqrstvwxyz
|
||||||
|
// digits not used: 0123456789
|
||||||
|
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
|
||||||
|
// letters duplicated: none
|
||||||
|
#define GETOPTS "hp:u:g:c:"
|
||||||
|
|
||||||
|
#define USAGE \
|
||||||
|
"\
|
||||||
|
usage: pledge.com [-h] PROG ARGS...\n\
|
||||||
|
-h show help\n\
|
||||||
|
-g GID call setgid()\n\
|
||||||
|
-u UID call setuid()\n\
|
||||||
|
-c PATH call chroot()\n\
|
||||||
|
-p PLEDGE may contain any of following separated by spaces\n\
|
||||||
|
- stdio: allow stdio and benign system calls\n\
|
||||||
|
- rpath: read-only path ops\n\
|
||||||
|
- wpath: write path ops\n\
|
||||||
|
- cpath: create path ops\n\
|
||||||
|
- dpath: create special files\n\
|
||||||
|
- flock: file locks\n\
|
||||||
|
- tty: terminal ioctls\n\
|
||||||
|
- recvfd: allow SCM_RIGHTS\n\
|
||||||
|
- fattr: allow changing some struct stat bits\n\
|
||||||
|
- inet: allow IPv4 and IPv6\n\
|
||||||
|
- unix: allow local sockets\n\
|
||||||
|
- dns: allow dns\n\
|
||||||
|
- proc: allow fork, clone and friends\n\
|
||||||
|
- thread: allow clone\n\
|
||||||
|
- id: allow setuid and friends\n\
|
||||||
|
- exec: allow executing ape binaries\n\
|
||||||
|
"
|
||||||
|
|
||||||
|
int g_gflag;
|
||||||
|
int g_uflag;
|
||||||
|
int g_hflag;
|
||||||
|
const char *g_pflag;
|
||||||
|
const char *g_cflag;
|
||||||
|
|
||||||
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
|
int opt;
|
||||||
|
g_pflag = "";
|
||||||
|
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'p':
|
||||||
|
g_pflag = optarg;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
g_cflag = optarg;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
g_gflag = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
g_uflag = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
write(1, USAGE, sizeof(USAGE) - 1);
|
||||||
|
exit(0);
|
||||||
|
default:
|
||||||
|
write(2, USAGE, sizeof(USAGE) - 1);
|
||||||
|
exit(64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *prog;
|
||||||
|
char pledges[1024];
|
||||||
|
char pathbuf[PATH_MAX];
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
GetOpts(argc, argv);
|
||||||
|
if (optind == argc) {
|
||||||
|
kprintf("error: too few args\n", g_pflag);
|
||||||
|
write(2, USAGE, sizeof(USAGE) - 1);
|
||||||
|
exit(64);
|
||||||
|
}
|
||||||
|
if (g_cflag) {
|
||||||
|
if (chroot(g_cflag) == -1) {
|
||||||
|
kprintf("error: chroot(%`'s) failed: %s\n", g_cflag, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(prog = commandv(argv[optind], pathbuf, sizeof(pathbuf)))) {
|
||||||
|
kprintf("error: command not found: %s\n", argv[optind]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (g_gflag) {
|
||||||
|
if (setgid(g_gflag) == -1) {
|
||||||
|
kprintf("error: setgid(%d) failed: %s\n", g_gflag, strerror(errno));
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g_uflag) {
|
||||||
|
if (setuid(g_uflag) == -1) {
|
||||||
|
kprintf("error: setuid(%d) failed: %s\n", g_uflag, strerror(errno));
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ksnprintf(pledges, sizeof(pledges), "%s execnative", g_pflag);
|
||||||
|
if (pledge(pledges, 0) == -1) {
|
||||||
|
kprintf("error: pledge(%`'s) failed: %s\n", pledges, strerror(errno));
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
execv(prog, argv + optind);
|
||||||
|
kprintf("error: execve(%`'s) failed: %s\n", prog, strerror(errno));
|
||||||
|
return 127;
|
||||||
|
}
|
|
@ -765,7 +765,7 @@ FUNCTIONS
|
||||||
|
|
||||||
If the raw length of a table is reported as zero, then we
|
If the raw length of a table is reported as zero, then we
|
||||||
check for the magic element `[0]=false`. If it's present, then
|
check for the magic element `[0]=false`. If it's present, then
|
||||||
your table will be serialized as empty array `[]`. That entry
|
your table will be serialized as empty array `[]`. An entry is
|
||||||
inserted by DecodeJson() automatically, only when encountering
|
inserted by DecodeJson() automatically, only when encountering
|
||||||
empty arrays, and it's necessary in order to make empty arrays
|
empty arrays, and it's necessary in order to make empty arrays
|
||||||
round-trip. If raw length is zero and `[0]=false` is absent,
|
round-trip. If raw length is zero and `[0]=false` is absent,
|
||||||
|
|
Loading…
Reference in a new issue