mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-29 16:52:28 +00:00
Plug a hole in pledge()
Günther Noack points out that O_RDONLY|O_TRUNC will modify a file.
This commit is contained in:
parent
3443039f34
commit
e98514cdb7
6 changed files with 275 additions and 167 deletions
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/bpf.h"
|
||||
|
@ -233,6 +234,7 @@ static const uint16_t kPledgeLinuxWpath[] = {
|
|||
static const uint16_t kPledgeLinuxCpath[] = {
|
||||
__NR_linux_open | CREATONLY, //
|
||||
__NR_linux_openat | CREATONLY, //
|
||||
__NR_linux_creat | RESTRICT, //
|
||||
__NR_linux_rename, //
|
||||
__NR_linux_renameat, //
|
||||
__NR_linux_renameat2, //
|
||||
|
@ -445,20 +447,18 @@ static const struct sock_filter kFilterEnd[] = {
|
|||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA)),
|
||||
};
|
||||
|
||||
static bool AppendFilter(struct Filter *f, struct sock_filter *p, size_t n) {
|
||||
if (f->n + n <= ARRAYLEN(f->p)) {
|
||||
static void AppendFilter(struct Filter *f, struct sock_filter *p, size_t n) {
|
||||
if (UNLIKELY(f->n + n > ARRAYLEN(f->p))) {
|
||||
asm("hlt"); // need to increase array size
|
||||
unreachable;
|
||||
}
|
||||
memcpy(f->p + f->n, p, n * sizeof(*f->p));
|
||||
f->n += n;
|
||||
return true;
|
||||
} else {
|
||||
enomem();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// SYSCALL is only allowed in the .privileged section
|
||||
// We assume program image is loaded in 32-bit spaces
|
||||
static bool AppendOriginVerification(struct Filter *f, long ipromises) {
|
||||
static void AppendOriginVerification(struct Filter *f) {
|
||||
intptr_t x = (intptr_t)__privileged_start;
|
||||
intptr_t y = (intptr_t)__privileged_end;
|
||||
assert(0 < x && x < y && y < INT_MAX);
|
||||
|
@ -472,7 +472,7 @@ static bool AppendOriginVerification(struct Filter *f, long ipromises) {
|
|||
/*L6*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L7*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The first argument of sys_clone_linux() must NOT have:
|
||||
|
@ -481,7 +481,7 @@ static bool AppendOriginVerification(struct Filter *f, long ipromises) {
|
|||
// - CLONE_PTRACE (0x00002000)
|
||||
// - CLONE_UNTRACED (0x00800000)
|
||||
//
|
||||
static bool AllowCloneRestrict(struct Filter *f) {
|
||||
static void AllowCloneRestrict(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_clone, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||
|
@ -491,7 +491,7 @@ static bool AllowCloneRestrict(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The first argument of sys_clone_linux() must have:
|
||||
|
@ -508,7 +508,7 @@ static bool AllowCloneRestrict(struct Filter *f) {
|
|||
// - CLONE_PTRACE (0x00002000)
|
||||
// - CLONE_UNTRACED (0x00800000)
|
||||
//
|
||||
static bool AllowCloneThread(struct Filter *f) {
|
||||
static void AllowCloneThread(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_clone, 0, 9 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||
|
@ -521,7 +521,7 @@ static bool AllowCloneThread(struct Filter *f) {
|
|||
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L9*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The second argument of ioctl() must be one of:
|
||||
|
@ -531,7 +531,7 @@ static bool AllowCloneThread(struct Filter *f) {
|
|||
// - FIOCLEX (0x5451)
|
||||
// - FIONCLEX (0x5450)
|
||||
//
|
||||
static bool AllowIoctlStdio(struct Filter *f) {
|
||||
static void AllowIoctlStdio(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 8 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -543,7 +543,7 @@ static bool AllowIoctlStdio(struct Filter *f) {
|
|||
/*L7*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L8*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The second argument of ioctl() must be one of:
|
||||
|
@ -561,7 +561,7 @@ static bool AllowIoctlStdio(struct Filter *f) {
|
|||
// - TCSBRK (0x5409)
|
||||
// - TIOCSBRK (0x5427)
|
||||
//
|
||||
static bool AllowIoctlTty(struct Filter *f) {
|
||||
static void AllowIoctlTty(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 16 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -581,7 +581,7 @@ static bool AllowIoctlTty(struct Filter *f) {
|
|||
/*L15*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L16*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The level argument of setsockopt() must be one of:
|
||||
|
@ -609,7 +609,7 @@ static bool AllowIoctlTty(struct Filter *f) {
|
|||
// - TCP_FASTOPEN (0x17)
|
||||
// - TCP_FASTOPEN_CONNECT (0x1e)
|
||||
//
|
||||
static bool AllowSetsockoptRestrict(struct Filter *f) {
|
||||
static void AllowSetsockoptRestrict(struct Filter *f) {
|
||||
static const int nr = __NR_linux_setsockopt;
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 21 - 1),
|
||||
|
@ -636,7 +636,7 @@ static bool AllowSetsockoptRestrict(struct Filter *f) {
|
|||
/*L20*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L21*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The level argument of getsockopt() must be one of:
|
||||
|
@ -653,7 +653,7 @@ static bool AllowSetsockoptRestrict(struct Filter *f) {
|
|||
// - SO_RCVTIMEO (0x14)
|
||||
// - SO_SNDTIMEO (0x15)
|
||||
//
|
||||
static bool AllowGetsockoptRestrict(struct Filter *f) {
|
||||
static void AllowGetsockoptRestrict(struct Filter *f) {
|
||||
static const int nr = __NR_linux_getsockopt;
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 13 - 1),
|
||||
|
@ -671,7 +671,7 @@ static bool AllowGetsockoptRestrict(struct Filter *f) {
|
|||
/*L12*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L13*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The flags parameter of mmap() must not have:
|
||||
|
@ -680,7 +680,7 @@ static bool AllowGetsockoptRestrict(struct Filter *f) {
|
|||
// - MAP_NONBLOCK (0x10000)
|
||||
// - MAP_HUGETLB (0x40000)
|
||||
//
|
||||
static bool AllowMmapExec(struct Filter *f) {
|
||||
static void AllowMmapExec(struct Filter *f) {
|
||||
intptr_t y = (intptr_t)__privileged_end;
|
||||
assert(0 < y && y < INT_MAX);
|
||||
struct sock_filter fragment[] = {
|
||||
|
@ -692,7 +692,7 @@ static bool AllowMmapExec(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The prot parameter of mmap() may only have:
|
||||
|
@ -708,7 +708,7 @@ static bool AllowMmapExec(struct Filter *f) {
|
|||
// - MAP_NONBLOCK (0x10000)
|
||||
// - MAP_HUGETLB (0x40000)
|
||||
//
|
||||
static bool AllowMmapNoexec(struct Filter *f) {
|
||||
static void AllowMmapNoexec(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_mmap, 0, 9 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])), // prot
|
||||
|
@ -721,7 +721,7 @@ static bool AllowMmapNoexec(struct Filter *f) {
|
|||
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L9*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The prot parameter of mprotect() may only have:
|
||||
|
@ -730,7 +730,7 @@ static bool AllowMmapNoexec(struct Filter *f) {
|
|||
// - PROT_READ (1)
|
||||
// - PROT_WRITE (2)
|
||||
//
|
||||
static bool AllowMprotectNoexec(struct Filter *f) {
|
||||
static void AllowMprotectNoexec(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_mprotect, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])), // prot
|
||||
|
@ -740,84 +740,119 @@ static bool AllowMprotectNoexec(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The open() system call is permitted only when
|
||||
//
|
||||
// - (flags & O_ACCMODE) == O_RDONLY
|
||||
//
|
||||
static bool AllowOpenReadonly(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, O_ACCMODE),
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_RDONLY, 0, 1),
|
||||
/*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 flags parameter of open() must not have:
|
||||
//
|
||||
// - O_WRONLY (1)
|
||||
// - O_RDWR (2)
|
||||
// - O_CREAT (000000100)
|
||||
// - O_TRUNC (000001000)
|
||||
// - __O_TMPFILE (020000000)
|
||||
//
|
||||
static bool AllowOpenatReadonly(struct Filter *f) {
|
||||
static void AllowOpenReadonly(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])),
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_open, 0, 9 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/*L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, O_ACCMODE),
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_RDONLY, 0, 1),
|
||||
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_RDONLY, 0, 8 - 4),
|
||||
/*L4*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/*L5*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 020001100),
|
||||
/*L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 1),
|
||||
/*L7*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L9*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The open() system call is permitted only when
|
||||
//
|
||||
// - (flags & O_ACCMODE) == O_RDONLY
|
||||
//
|
||||
// The flags parameter of open() must not have:
|
||||
//
|
||||
// - O_CREAT (000000100)
|
||||
// - O_TRUNC (000001000)
|
||||
// - __O_TMPFILE (020000000)
|
||||
//
|
||||
static void AllowOpenatReadonly(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_openat, 0, 9 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
/*L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, O_ACCMODE),
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_RDONLY, 0, 8 - 4),
|
||||
/*L4*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
/*L5*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 020001100),
|
||||
/*L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 1),
|
||||
/*L7*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L9*/ /* next filter */
|
||||
};
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The open() system call is permitted only when
|
||||
//
|
||||
// - (flags & O_ACCMODE) == O_WRONLY
|
||||
// - (flags & O_ACCMODE) == O_RDWR
|
||||
//
|
||||
// The open() flags parameter must not contain
|
||||
//
|
||||
// - O_CREAT (000000100)
|
||||
// - O_TMPFILE (020200000)
|
||||
// - __O_TMPFILE (020000000)
|
||||
//
|
||||
static bool AllowOpenWriteonly(struct Filter *f) {
|
||||
static void 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, 1),
|
||||
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_open, 0, 10 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/* L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, O_ACCMODE),
|
||||
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_WRONLY, 1, 0),
|
||||
/* L4*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_RDWR, 0, 9 - 5),
|
||||
/* L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/* L6*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 020000100),
|
||||
/* L7*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 1),
|
||||
/* L8*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/* L9*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L10*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The open() system call is permitted only when
|
||||
//
|
||||
// - (flags & O_ACCMODE) == O_WRONLY
|
||||
// - (flags & O_ACCMODE) == O_RDWR
|
||||
//
|
||||
// The openat() flags parameter must not contain
|
||||
//
|
||||
// - O_CREAT (000000100)
|
||||
// - O_TMPFILE (020200000)
|
||||
// - __O_TMPFILE (020000000)
|
||||
//
|
||||
static bool AllowOpenatWriteonly(struct Filter *f) {
|
||||
static void 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, 1),
|
||||
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_openat, 0, 10 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
/* L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, O_ACCMODE),
|
||||
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_WRONLY, 1, 0),
|
||||
/* L4*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, O_RDWR, 0, 9 - 5),
|
||||
/* L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
/* L6*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 020000100),
|
||||
/* L7*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 1),
|
||||
/* L8*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/* L9*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L10*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// If the flags parameter of open() has one of:
|
||||
//
|
||||
// - O_CREAT (000000100)
|
||||
// - O_TMPFILE (020200000)
|
||||
// - __O_TMPFILE (020000000)
|
||||
//
|
||||
// Then the mode parameter must not have:
|
||||
//
|
||||
|
@ -825,7 +860,7 @@ static bool AllowOpenatWriteonly(struct Filter *f) {
|
|||
// - S_ISGID (02000 setgid)
|
||||
// - S_ISUID (04000 setuid)
|
||||
//
|
||||
static bool AllowOpenCreatonly(struct Filter *f) {
|
||||
static void AllowOpenCreatonly(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_open, 0, 12 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -841,13 +876,13 @@ static bool AllowOpenCreatonly(struct Filter *f) {
|
|||
/*L11*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L12*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// If the flags parameter of openat() has one of:
|
||||
//
|
||||
// - O_CREAT (000000100)
|
||||
// - O_TMPFILE (020200000)
|
||||
// - __O_TMPFILE (020000000)
|
||||
//
|
||||
// Then the mode parameter must not have:
|
||||
//
|
||||
|
@ -855,7 +890,7 @@ static bool AllowOpenCreatonly(struct Filter *f) {
|
|||
// - S_ISGID (02000 setgid)
|
||||
// - S_ISUID (04000 setuid)
|
||||
//
|
||||
static bool AllowOpenatCreatonly(struct Filter *f) {
|
||||
static void AllowOpenatCreatonly(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_openat, 0, 12 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
|
@ -871,7 +906,26 @@ static bool AllowOpenatCreatonly(struct Filter *f) {
|
|||
/*L11*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L12*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// Then the mode parameter must not have:
|
||||
//
|
||||
// - S_ISVTX (01000 sticky)
|
||||
// - S_ISGID (02000 setgid)
|
||||
// - S_ISUID (04000 setuid)
|
||||
//
|
||||
static void AllowCreatRestrict(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_creat, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/*L2*/ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 07000),
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 1),
|
||||
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The second argument of fcntl() must be one of:
|
||||
|
@ -883,7 +937,7 @@ static bool AllowOpenatCreatonly(struct Filter *f) {
|
|||
// - F_GETFL (3)
|
||||
// - F_SETFL (4)
|
||||
//
|
||||
static bool AllowFcntlStdio(struct Filter *f) {
|
||||
static void AllowFcntlStdio(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fcntl, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -893,7 +947,7 @@ static bool AllowFcntlStdio(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The second argument of fcntl() must be one of:
|
||||
|
@ -902,7 +956,7 @@ static bool AllowFcntlStdio(struct Filter *f) {
|
|||
// - F_SETLK (6)
|
||||
// - F_SETLKW (7)
|
||||
//
|
||||
static bool AllowFcntlLock(struct Filter *f) {
|
||||
static void AllowFcntlLock(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fcntl, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -912,14 +966,14 @@ static bool AllowFcntlLock(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The addr parameter of sendto() must be
|
||||
//
|
||||
// - NULL
|
||||
//
|
||||
static bool AllowSendtoAddrless(struct Filter *f) {
|
||||
static void AllowSendtoAddrless(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_sendto, 0, 7 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[4]) + 0),
|
||||
|
@ -930,14 +984,14 @@ static bool AllowSendtoAddrless(struct Filter *f) {
|
|||
/*L6*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L7*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The sig parameter of sigaction() must NOT be
|
||||
//
|
||||
// - SIGSYS (31)
|
||||
//
|
||||
static bool AllowSigactionNosigsys(struct Filter *f) {
|
||||
static void AllowSigactionNosigsys(struct Filter *f) {
|
||||
static const int nr = __NR_linux_sigaction;
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 5 - 1),
|
||||
|
@ -947,7 +1001,7 @@ static bool AllowSigactionNosigsys(struct Filter *f) {
|
|||
/*L4*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L5*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The family parameter of socket() must be one of:
|
||||
|
@ -972,7 +1026,7 @@ static bool AllowSigactionNosigsys(struct Filter *f) {
|
|||
// - IPPROTO_TCP (0x06)
|
||||
// - IPPROTO_UDP (0x11)
|
||||
//
|
||||
static bool AllowSocketInet(struct Filter *f) {
|
||||
static void AllowSocketInet(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_socket, 0, 15 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||
|
@ -991,7 +1045,7 @@ static bool AllowSocketInet(struct Filter *f) {
|
|||
/*L14*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L15*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The family parameter of socket() must be one of:
|
||||
|
@ -1013,7 +1067,7 @@ static bool AllowSocketInet(struct Filter *f) {
|
|||
//
|
||||
// - 0
|
||||
//
|
||||
static bool AllowSocketUnix(struct Filter *f) {
|
||||
static void AllowSocketUnix(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_socket, 0, 11 - 1),
|
||||
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||
|
@ -1028,7 +1082,7 @@ static bool AllowSocketUnix(struct Filter *f) {
|
|||
/*L10*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L11*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The first parameter of prctl() can be any of
|
||||
|
@ -1040,7 +1094,7 @@ static bool AllowSocketUnix(struct Filter *f) {
|
|||
// - PR_SET_NO_NEW_PRIVS (38)
|
||||
// - PR_CAPBSET_READ (23)
|
||||
//
|
||||
static bool AllowPrctlStdio(struct Filter *f) {
|
||||
static void AllowPrctlStdio(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_prctl, 0, 10 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||
|
@ -1054,7 +1108,7 @@ static bool AllowPrctlStdio(struct Filter *f) {
|
|||
/*L8*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L9*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The mode parameter of chmod() can't have the following:
|
||||
|
@ -1063,7 +1117,7 @@ static bool AllowPrctlStdio(struct Filter *f) {
|
|||
// - S_ISGID (02000 setgid)
|
||||
// - S_ISUID (04000 setuid)
|
||||
//
|
||||
static bool AllowChmodNobits(struct Filter *f) {
|
||||
static void AllowChmodNobits(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_chmod, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -1073,7 +1127,7 @@ static bool AllowChmodNobits(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The mode parameter of fchmod() can't have the following:
|
||||
|
@ -1082,7 +1136,7 @@ static bool AllowChmodNobits(struct Filter *f) {
|
|||
// - S_ISGID (02000 setgid)
|
||||
// - S_ISUID (04000 setuid)
|
||||
//
|
||||
static bool AllowFchmodNobits(struct Filter *f) {
|
||||
static void AllowFchmodNobits(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fchmod, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
|
@ -1092,7 +1146,7 @@ static bool AllowFchmodNobits(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The mode parameter of fchmodat() can't have the following:
|
||||
|
@ -1101,7 +1155,7 @@ static bool AllowFchmodNobits(struct Filter *f) {
|
|||
// - S_ISGID (02000 setgid)
|
||||
// - S_ISUID (04000 setuid)
|
||||
//
|
||||
static bool AllowFchmodatNobits(struct Filter *f) {
|
||||
static void AllowFchmodatNobits(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fchmodat, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
|
@ -1111,14 +1165,14 @@ static bool AllowFchmodatNobits(struct Filter *f) {
|
|||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
// The new_limit parameter of prlimit() must be
|
||||
//
|
||||
// - NULL (0)
|
||||
//
|
||||
static bool AllowPrlimitStdio(struct Filter *f) {
|
||||
static void AllowPrlimitStdio(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_prlimit, 0, 7 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
|
||||
|
@ -1129,7 +1183,7 @@ static bool AllowPrlimitStdio(struct Filter *f) {
|
|||
/*L6*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L7*/ /* next filter */
|
||||
};
|
||||
return AppendFilter(f, PLEDGE(fragment));
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
||||
static int CountUnspecial(const uint16_t *p, size_t len) {
|
||||
|
@ -1142,7 +1196,7 @@ static int CountUnspecial(const uint16_t *p, size_t len) {
|
|||
return count;
|
||||
}
|
||||
|
||||
static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len) {
|
||||
static void AppendPledge(struct Filter *f, const uint16_t *p, size_t len) {
|
||||
int i, j, count;
|
||||
|
||||
// handle ordinals which allow syscalls regardless of args
|
||||
|
@ -1158,17 +1212,13 @@ static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len) {
|
|||
count - j - 1, // jump if true displacement
|
||||
j == count - 1), // jump if false displacement
|
||||
};
|
||||
if (!AppendFilter(f, PLEDGE(fragment))) {
|
||||
return false;
|
||||
}
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
++j;
|
||||
}
|
||||
struct sock_filter fragment[] = {
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
if (!AppendFilter(f, PLEDGE(fragment))) {
|
||||
return false;
|
||||
}
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
} else {
|
||||
asm("hlt"); // list of ordinals exceeds max displacement
|
||||
unreachable;
|
||||
|
@ -1180,123 +1230,113 @@ static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len) {
|
|||
if (!(p[i] & SPECIAL)) continue;
|
||||
switch (p[i]) {
|
||||
case __NR_linux_mmap | EXEC:
|
||||
if (!AllowMmapExec(f)) return false;
|
||||
AllowMmapExec(f);
|
||||
break;
|
||||
case __NR_linux_mmap | NOEXEC:
|
||||
if (!AllowMmapNoexec(f)) return false;
|
||||
AllowMmapNoexec(f);
|
||||
break;
|
||||
case __NR_linux_mprotect | NOEXEC:
|
||||
if (!AllowMprotectNoexec(f)) return false;
|
||||
AllowMprotectNoexec(f);
|
||||
break;
|
||||
case __NR_linux_chmod | NOBITS:
|
||||
if (!AllowChmodNobits(f)) return false;
|
||||
AllowChmodNobits(f);
|
||||
break;
|
||||
case __NR_linux_fchmod | NOBITS:
|
||||
if (!AllowFchmodNobits(f)) return false;
|
||||
AllowFchmodNobits(f);
|
||||
break;
|
||||
case __NR_linux_fchmodat | NOBITS:
|
||||
if (!AllowFchmodatNobits(f)) return false;
|
||||
AllowFchmodatNobits(f);
|
||||
break;
|
||||
case __NR_linux_sigaction | NOSIGSYS:
|
||||
if (!AllowSigactionNosigsys(f)) return false;
|
||||
AllowSigactionNosigsys(f);
|
||||
break;
|
||||
case __NR_linux_prctl | STDIO:
|
||||
if (!AllowPrctlStdio(f)) return false;
|
||||
AllowPrctlStdio(f);
|
||||
break;
|
||||
case __NR_linux_open | CREATONLY:
|
||||
if (!AllowOpenCreatonly(f)) return false;
|
||||
AllowOpenCreatonly(f);
|
||||
break;
|
||||
case __NR_linux_openat | CREATONLY:
|
||||
if (!AllowOpenatCreatonly(f)) return false;
|
||||
AllowOpenatCreatonly(f);
|
||||
break;
|
||||
case __NR_linux_open | READONLY:
|
||||
if (!AllowOpenReadonly(f)) return false;
|
||||
AllowOpenReadonly(f);
|
||||
break;
|
||||
case __NR_linux_openat | READONLY:
|
||||
if (!AllowOpenatReadonly(f)) return false;
|
||||
AllowOpenatReadonly(f);
|
||||
break;
|
||||
case __NR_linux_open | WRITEONLY:
|
||||
if (!AllowOpenWriteonly(f)) return false;
|
||||
AllowOpenWriteonly(f);
|
||||
break;
|
||||
case __NR_linux_openat | WRITEONLY:
|
||||
if (!AllowOpenatWriteonly(f)) return false;
|
||||
AllowOpenatWriteonly(f);
|
||||
break;
|
||||
case __NR_linux_setsockopt | RESTRICT:
|
||||
if (!AllowSetsockoptRestrict(f)) return false;
|
||||
AllowSetsockoptRestrict(f);
|
||||
break;
|
||||
case __NR_linux_getsockopt | RESTRICT:
|
||||
if (!AllowGetsockoptRestrict(f)) return false;
|
||||
AllowGetsockoptRestrict(f);
|
||||
break;
|
||||
case __NR_linux_creat | RESTRICT:
|
||||
AllowCreatRestrict(f);
|
||||
break;
|
||||
case __NR_linux_fcntl | STDIO:
|
||||
if (!AllowFcntlStdio(f)) return false;
|
||||
AllowFcntlStdio(f);
|
||||
break;
|
||||
case __NR_linux_fcntl | LOCK:
|
||||
if (!AllowFcntlLock(f)) return false;
|
||||
AllowFcntlLock(f);
|
||||
break;
|
||||
case __NR_linux_ioctl | RESTRICT:
|
||||
if (!AllowIoctlStdio(f)) return false;
|
||||
AllowIoctlStdio(f);
|
||||
break;
|
||||
case __NR_linux_ioctl | TTY:
|
||||
if (!AllowIoctlTty(f)) return false;
|
||||
AllowIoctlTty(f);
|
||||
break;
|
||||
case __NR_linux_socket | INET:
|
||||
if (!AllowSocketInet(f)) return false;
|
||||
AllowSocketInet(f);
|
||||
break;
|
||||
case __NR_linux_socket | UNIX:
|
||||
if (!AllowSocketUnix(f)) return false;
|
||||
AllowSocketUnix(f);
|
||||
break;
|
||||
case __NR_linux_sendto | ADDRLESS:
|
||||
if (!AllowSendtoAddrless(f)) return false;
|
||||
AllowSendtoAddrless(f);
|
||||
break;
|
||||
case __NR_linux_clone | RESTRICT:
|
||||
if (!AllowCloneRestrict(f)) return false;
|
||||
AllowCloneRestrict(f);
|
||||
break;
|
||||
case __NR_linux_clone | THREAD:
|
||||
if (!AllowCloneThread(f)) return false;
|
||||
AllowCloneThread(f);
|
||||
break;
|
||||
case __NR_linux_prlimit | STDIO:
|
||||
if (!AllowPrlimitStdio(f)) return false;
|
||||
AllowPrlimitStdio(f);
|
||||
break;
|
||||
default:
|
||||
asm("hlt"); // switch forgot to define a special ordinal
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int sys_pledge_linux(unsigned long ipromises) {
|
||||
bool ok = true;
|
||||
int i, rc = -1;
|
||||
struct Filter f;
|
||||
CheckLargeStackAllocation(&f, sizeof(f));
|
||||
f.n = 0;
|
||||
ipromises = ~ipromises;
|
||||
if (AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
|
||||
((ipromises & (1ul << PROMISE_EXEC)) ||
|
||||
AppendOriginVerification(&f, ipromises)) &&
|
||||
AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault))) {
|
||||
AppendFilter(&f, PLEDGE(kFilterStart));
|
||||
if (!(~ipromises & (1ul << PROMISE_EXEC))) {
|
||||
AppendOriginVerification(&f);
|
||||
}
|
||||
AppendPledge(&f, PLEDGE(kPledgeLinuxDefault));
|
||||
for (i = 0; i < ARRAYLEN(kPledgeLinux); ++i) {
|
||||
if ((ipromises & (1ul << i)) && kPledgeLinux[i].name) {
|
||||
ipromises &= ~(1ul << i);
|
||||
if (!AppendPledge(&f, kPledgeLinux[i].syscalls, kPledgeLinux[i].len)) {
|
||||
ok = false;
|
||||
rc = einval();
|
||||
break;
|
||||
if (~ipromises & (1ul << i)) {
|
||||
AppendPledge(&f, kPledgeLinux[i].syscalls, kPledgeLinux[i].len);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipromises) {
|
||||
ok = false;
|
||||
rc = einval();
|
||||
}
|
||||
if (ok && AppendFilter(&f, kFilterEnd, ARRAYLEN(kFilterEnd)) &&
|
||||
(rc = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) != -1) {
|
||||
AppendFilter(&f, PLEDGE(kFilterEnd));
|
||||
if ((rc = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) != -1) {
|
||||
struct sock_fprog sandbox = {.len = f.n, .filter = f.p};
|
||||
rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sandbox);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1530,7 +1570,7 @@ int pledge(const char *promises, const char *execpromises) {
|
|||
} else {
|
||||
rc = sys_pledge(promises, execpromises);
|
||||
}
|
||||
if (!rc && (IsOpenbsd() || getpid() == gettid())) {
|
||||
if (!rc && (IsOpenbsd() || (IsLinux() && getpid() == gettid()))) {
|
||||
__promises = ipromises;
|
||||
__execpromises = iexecpromises;
|
||||
}
|
||||
|
|
41
libc/runtime/mapshared.c
Normal file
41
libc/runtime/mapshared.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- 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/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
/**
|
||||
* Creates anonymous shared memory mapping.
|
||||
*
|
||||
* @return memory map address on success, or null w/ errno
|
||||
*/
|
||||
void *_mapshared(size_t size) {
|
||||
void *m;
|
||||
m = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (m != MAP_FAILED) {
|
||||
return m;
|
||||
}
|
||||
if (errno == ENOMEM && weaken(__oom_hook)) {
|
||||
weaken(__oom_hook)(size);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -48,6 +48,7 @@ void mcount(void);
|
|||
int _freestack(void *);
|
||||
unsigned long getauxval(unsigned long);
|
||||
void *_mapanon(size_t) attributeallocsize((1)) mallocesque;
|
||||
void *_mapshared(size_t) attributeallocsize((1)) mallocesque;
|
||||
void *_mapstack(void) returnsaligned((FRAMESIZE)) mallocesque;
|
||||
int setjmp(jmp_buf) libcesque returnstwice paramsnonnull();
|
||||
void longjmp(jmp_buf, int) libcesque wontreturn paramsnonnull();
|
||||
|
|
|
@ -196,7 +196,7 @@ syscon open O_SEQUENTIAL 0 0 0 0 0 0x40000000 # kNtFileFlagSequen
|
|||
syscon open O_COMPRESSED 0 0 0 0 0 0x20000000 # kNtFileAttributeCompressed [SYNC libc/calls/open-nt.c]
|
||||
syscon open O_INDEXED 0 0 0 0 0 0x10000000 # !kNtFileAttributeNotContentIndexed [SYNC libc/calls/open-nt.c]
|
||||
syscon open O_CLOEXEC 0x00080000 0x01000000 0x00100000 0x00010000 0x00400000 0x00080000 # NT faked as Linux [SYNC libc/calls/open-nt.c]
|
||||
syscon open O_TMPFILE 0x00410000 0 0 0 0 0x00410000 # Linux 3.11+ (c. 2013) & kNtFileAttributeTemporary|kNtFileFlagDeleteOnClose [SYNC libc/calls/open-nt.c]
|
||||
syscon open O_TMPFILE 0x00410000 0 0 0 0 0x00410000 # Linux 3.11+ (c. 2013) __O_TMPFILE | O_DIRECTORY; kNtFileAttributeTemporary|kNtFileFlagDeleteOnClose [SYNC libc/calls/open-nt.c]
|
||||
syscon open O_SPARSE 0 0 0 0 0 0 # wut
|
||||
syscon open O_NONBLOCK 0x00000800 0x00000004 0x00000004 0x00000004 0x00000004 0x00000800 # bsd consensus
|
||||
syscon open O_ASYNC 0x00002000 0x00000040 0x00000040 0x00000040 0x00000040 0 # bsd consensus
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
|
||||
|
@ -266,6 +267,30 @@ TEST(pledge, unix_forbidsInetSockets) {
|
|||
EXPECT_TRUE(WIFEXITED(ws) && !WEXITSTATUS(ws));
|
||||
}
|
||||
|
||||
TEST(pledge, wpath_doesNotImplyRpath) {
|
||||
int ws, pid;
|
||||
bool *gotsome;
|
||||
ASSERT_NE(-1, (gotsome = _mapshared(FRAMESIZE)));
|
||||
ASSERT_SYS(0, 0, touch("foo", 0644));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio wpath", 0));
|
||||
ASSERT_SYS(0, 3, open("foo", O_WRONLY));
|
||||
*gotsome = true;
|
||||
ASSERT_SYS(EPERM, -1, open("foo", O_RDONLY));
|
||||
_Exit(0);
|
||||
}
|
||||
EXPECT_NE(-1, wait(&ws));
|
||||
ASSERT_TRUE(*gotsome);
|
||||
if (IsOpenbsd()) {
|
||||
ASSERT_TRUE(WIFSIGNALED(ws));
|
||||
ASSERT_EQ(SIGABRT, WTERMSIG(ws));
|
||||
} else {
|
||||
ASSERT_TRUE(WIFEXITED(ws));
|
||||
ASSERT_EQ(0, WEXITSTATUS(ws));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(pledge, inet_forbidsOtherSockets) {
|
||||
if (IsOpenbsd()) return; // b/c testing linux bpf
|
||||
int ws, pid;
|
||||
|
@ -378,6 +403,8 @@ TEST(pledge, open_rpath) {
|
|||
if (!pid) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio rpath", 0));
|
||||
ASSERT_SYS(0, 3, open("foo", O_RDONLY));
|
||||
ASSERT_SYS(EPERM, -1, open("foo", O_RDONLY | O_TRUNC));
|
||||
ASSERT_SYS(EPERM, -1, open("foo", O_RDONLY | O_TMPFILE));
|
||||
ASSERT_SYS(EPERM, -1, open("foo", O_RDWR | O_TRUNC | O_CREAT, 0644));
|
||||
ASSERT_SYS(EPERM, -1, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
||||
_Exit(0);
|
||||
|
@ -393,9 +420,9 @@ TEST(pledge, open_wpath) {
|
|||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio wpath", 0));
|
||||
ASSERT_SYS(0, 3, open("foo", O_RDONLY));
|
||||
ASSERT_SYS(EPERM, -1, open(".", O_RDWR | O_TMPFILE, 07644));
|
||||
ASSERT_SYS(0, 4, open("foo", O_WRONLY | O_TRUNC, 07644));
|
||||
ASSERT_SYS(0, 3, open("foo", O_WRONLY | O_TRUNC));
|
||||
ASSERT_SYS(0, 4, open("foo", O_RDWR));
|
||||
ASSERT_SYS(EPERM, -1, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
||||
_Exit(0);
|
||||
}
|
||||
|
|
|
@ -351,8 +351,7 @@ TEST(unveil, isThreadSpecificOnLinux_isProcessWideOnOpenbsd) {
|
|||
TEST(unveil, usedTwice_forbidden_worksWithPledge) {
|
||||
int ws, pid;
|
||||
bool *gotsome;
|
||||
ASSERT_NE(-1, (gotsome = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0)));
|
||||
ASSERT_NE(-1, (gotsome = _mapshared(FRAMESIZE)));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
// install our first seccomp filter
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue