Plug a hole in pledge()

Günther Noack points out that O_RDONLY|O_TRUNC will modify a file.
This commit is contained in:
Justine Tunney 2022-07-24 23:40:49 -07:00
parent 3443039f34
commit e98514cdb7
6 changed files with 275 additions and 167 deletions

View file

@ -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
View 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;
}

View file

@ -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();

View file

@ -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

View file

@ -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);
}

View file

@ -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