Add seccomp bpf sandboxing to redbean

It's now possible to pass the `-S` or `-SS` flags to sandbox redbean
worker proecsses after they've been forked. The first `-S` flag is
intended to be a permissive builtin policy that limits system calls to
only that which the various parts of redbean serving need. The second
`-SS` flag is intended to be more restrictive, preventing things like
the Lua extensions you download off the web from using the HTTP client
or sockets APIs. In upcoming changes you'll be able to implement your
own Berkeley Packet Filter sandbox programs and load them via Lua.
This commit is contained in:
Justine Tunney 2022-04-18 08:54:42 -07:00
parent 7166679620
commit 5a132f9652
79 changed files with 2271 additions and 651 deletions

View file

@ -1,10 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_ISSANDBOXED_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_ISSANDBOXED_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool __issandboxed;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_ISSANDBOXED_INTERNAL_H_ */

View file

@ -19,8 +19,22 @@
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/errno.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/errfuns.h"
static const char *DescribePrctlOperation(int x) {
switch (x) {
case PR_SET_NO_NEW_PRIVS:
return "PR_SET_NO_NEW_PRIVS";
case PR_SET_SECCOMP:
return "PR_SET_SECCOMP";
case PR_GET_SECCOMP:
return "PR_GET_SECCOMP";
default:
return "PRCTL_???";
}
}
/**
* Tunes process on Linux.
*
@ -47,6 +61,7 @@ int prctl(int operation, ...) {
} else {
rc = enosys();
}
STRACE("seccomp(%d, %p, %p, %p, %p) → %d% m", operation, a, b, c, d, rc);
STRACE("prctl(%s, %p, %p, %p, %p) → %d% m", DescribePrctlOperation(operation),
a, b, c, d, rc);
return rc;
}

View file

@ -42,8 +42,7 @@
*/
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
int i;
ssize_t rc, rem;
ssize_t rc;
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
@ -66,27 +65,16 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
} else {
rc = einval();
}
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("readv(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
} else {
rem = rc != -1 ? rc : 0;
kprintf(STRACE_PROLOGUE "readv(%d, [{", fd);
for (i = 0; i < MIN(5, iovlen); ++i) {
kprintf("%s{%#.*hhs%s, %'zu}", i ? ", " : "",
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))), iov[i].iov_base,
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))) < iov[i].iov_len
? "..."
: "",
iov[i].iov_len);
rem -= iov[i].iov_len;
}
kprintf("%s}], %d) → %'ld% m%n", iovlen > 5 ? "..." : "", iovlen, rc);
kprintf(STRACE_PROLOGUE "readv(%d, [", fd);
__strace_iov(iov, iovlen, rc != -1 ? rc : 0);
kprintf("], %d) → %'ld% m%n", iovlen, rc);
}
}
#endif
return rc;
}

View file

@ -17,15 +17,29 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/issandboxed.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/seccomp.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/seccomp.h"
#include "libc/sysv/errfuns.h"
static const char *DescribeSeccompOperation(int x) {
switch (x) {
case SECCOMP_SET_MODE_STRICT:
return "SECCOMP_SET_MODE_STRICT";
case SECCOMP_SET_MODE_FILTER:
return "SECCOMP_SET_MODE_FILTER";
case SECCOMP_GET_ACTION_AVAIL:
return "SECCOMP_GET_ACTION_AVAIL";
case SECCOMP_GET_NOTIF_SIZES:
return "SECCOMP_GET_NOTIF_SIZES";
default:
return "SECCOMP_???";
}
}
/**
* Tunes Linux security policy.
*
@ -63,7 +77,7 @@ int seccomp(unsigned operation, unsigned flags, void *args) {
} else {
rc = enosys();
}
STRACE("seccomp(%s, %#x, %p) → %d% m",
DescribeSeccompOperationFlags(operation), flags, args, rc);
STRACE("seccomp(%s, %#x, %p) → %d% m", DescribeSeccompOperation(operation),
flags, args, rc);
return rc;
}

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRACE_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRACE_INTERNAL_H_
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
@ -53,6 +54,7 @@ COSMOPOLITAN_C_START_
extern int __strace;
void __stracef(const char *, ...);
void __strace_iov(const struct iovec *, int, ssize_t);
const char *__strace_stat(int, const struct stat *);
const char *__strace_sigaction(char *, size_t, int, const struct sigaction *);
const char *__strace_sigset(char[41], size_t, int, const sigset_t *);

View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
void __strace_iov(const struct iovec *iov, int iovlen, ssize_t rem) {
int i;
kprintf("{");
for (i = 0; rem && i < MIN(5, iovlen); ++i) {
kprintf(
"%s{%#.*hhs%s, %'zu}", i ? ", " : "",
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))), iov[i].iov_base,
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))) < iov[i].iov_len ? "..." : "",
iov[i].iov_len);
rem -= iov[i].iov_len;
}
kprintf("%s}", iovlen > 5 ? "..." : "");
}

1341
libc/calls/struct/bpf.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,59 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_FILTER_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_FILTER_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define BPF_MAJOR_VERSION 1
#define BPF_MINOR_VERSION 1
struct sock_filter {
uint16_t code;
uint8_t jt;
uint8_t jf;
uint32_t k;
};
struct sock_fprog {
unsigned short len;
struct sock_filter *filter;
};
#define BPF_RVAL(code) ((code)&0x18)
#define BPF_A 0x10
#define BPF_MISCOP(code) ((code)&0xf8)
#define BPF_TAX 0x00
#define BPF_TXA 0x80
#define BPF_STMT(code, k) \
{ (unsigned short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) \
{ (unsigned short)(code), jt, jf, k }
#define BPF_MEMWORDS 16
#define SKF_AD_OFF (-0x1000)
#define SKF_AD_PROTOCOL 0
#define SKF_AD_PKTTYPE 4
#define SKF_AD_IFINDEX 8
#define SKF_AD_NLATTR 12
#define SKF_AD_NLATTR_NEST 16
#define SKF_AD_MARK 20
#define SKF_AD_QUEUE 24
#define SKF_AD_HATYPE 28
#define SKF_AD_RXHASH 32
#define SKF_AD_CPU 36
#define SKF_AD_ALU_XOR_X 40
#define SKF_AD_VLAN_TAG 44
#define SKF_AD_VLAN_TAG_PRESENT 48
#define SKF_AD_PAY_OFFSET 52
#define SKF_AD_RANDOM 56
#define SKF_AD_VLAN_TPID 60
#define SKF_AD_MAX 64
#define SKF_NET_OFF (-0x100000)
#define SKF_LL_OFF (-0x200000)
#define BPF_NET_OFF SKF_NET_OFF
#define BPF_LL_OFF SKF_LL_OFF
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_FILTER_H_ */

23
libc/calls/struct/hog.py Normal file
View file

@ -0,0 +1,23 @@
s="""
BPF_SOCK_OPS_VOID,
BPF_SOCK_OPS_TIMEOUT_INIT,
BPF_SOCK_OPS_RWND_INIT,
BPF_SOCK_OPS_TCP_CONNECT_CB,
BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB,
BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB,
BPF_SOCK_OPS_NEEDS_ECN,
BPF_SOCK_OPS_BASE_RTT,
BPF_SOCK_OPS_RTO_CB,
BPF_SOCK_OPS_RETRANS_CB,
BPF_SOCK_OPS_STATE_CB,
BPF_SOCK_OPS_TCP_LISTEN_CB,
BPF_SOCK_OPS_RTT_CB,
BPF_SOCK_OPS_PARSE_HDR_OPT_CB,
BPF_SOCK_OPS_HDR_OPT_LEN_CB,
BPF_SOCK_OPS_WRITE_HDR_OPT_CB,
"""
i = 0
for x in s.replace(',','').split():
print("#define %s %d" % (x, i))
i += 1

View file

@ -1,8 +1,45 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SECCOMP_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SECCOMP_H_
#define SECCOMP_SET_MODE_STRICT 0
#define SECCOMP_SET_MODE_FILTER 1
#define SECCOMP_GET_ACTION_AVAIL 2
#define SECCOMP_GET_NOTIF_SIZES 3
#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
#define SECCOMP_FILTER_FLAG_LOG (1UL << 1)
#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3)
#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4)
#define SECCOMP_RET_KILL_PROCESS 0x80000000U
#define SECCOMP_RET_KILL_THREAD 0x00000000U
#define SECCOMP_RET_KILL SECCOMP_RET_KILL_THREAD
#define SECCOMP_RET_TRAP 0x00030000U
#define SECCOMP_RET_ERRNO 0x00050000U
#define SECCOMP_RET_USER_NOTIF 0x7fc00000U
#define SECCOMP_RET_TRACE 0x7ff00000U
#define SECCOMP_RET_LOG 0x7ffc0000U
#define SECCOMP_RET_ALLOW 0x7fff0000U
#define SECCOMP_RET_ACTION_FULL 0xffff0000U
#define SECCOMP_RET_ACTION 0x7fff0000U
#define SECCOMP_RET_DATA 0x0000ffffU
#define SECCOMP_USER_NOTIF_FLAG_CONTINUE (1UL << 0)
#define SECCOMP_ADDFD_FLAG_SETFD (1UL << 0)
#define SECCOMP_ADDFD_FLAG_SEND (1UL << 1)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define SECCOMP_IOC_MAGIC '!'
#define SECCOMP_IO(nr) _IO(SECCOMP_IOC_MAGIC, nr)
#define SECCOMP_IOR(nr, type) _IOR(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOW(nr, type) _IOW(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOWR(nr, type) _IOWR(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOCTL_NOTIF_RECV SECCOMP_IOWR(0, struct seccomp_notif)
#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, struct seccomp_notif_resp)
#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOW(2, __u64)
#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, struct seccomp_notif_addfd)
struct seccomp_data {
int32_t nr;
uint32_t arch;
@ -38,17 +75,6 @@ struct seccomp_notif_addfd {
uint32_t newfd_flags;
};
#define SECCOMP_IOC_MAGIC '!'
#define SECCOMP_IO(nr) _IO(SECCOMP_IOC_MAGIC, nr)
#define SECCOMP_IOR(nr, type) _IOR(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOW(nr, type) _IOW(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOWR(nr, type) _IOWR(SECCOMP_IOC_MAGIC, nr, type)
#define SECCOMP_IOCTL_NOTIF_RECV SECCOMP_IOWR(0, struct seccomp_notif)
#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, struct seccomp_notif_resp)
#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOW(2, __u64)
#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, struct seccomp_notif_addfd)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SECCOMP_H_ */

View file

@ -47,7 +47,7 @@
*/
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
int i;
ssize_t rc, rem;
ssize_t rc;
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
@ -77,18 +77,9 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
if (rc == -1 && errno == EFAULT) {
STRACE("writev(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
} else {
rem = rc != -1 ? rc : 0;
kprintf(STRACE_PROLOGUE "writev(%d, {", fd);
for (i = 0; i < MIN(5, iovlen); ++i) {
kprintf("%s{%#.*hhs%s, %'zu}", i ? ", " : "",
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))), iov[i].iov_base,
MAX(0, MIN(40, MIN(rem, iov[i].iov_len))) < iov[i].iov_len
? "..."
: "",
iov[i].iov_len);
rem -= iov[i].iov_len;
}
kprintf("%s}, %d) → %'ld% m%n", iovlen > 5 ? "..." : "", iovlen, rc);
kprintf(STRACE_PROLOGUE "readv(%d, ", fd);
__strace_iov(iov, iovlen, rc != -1 ? rc : 0);
kprintf(", %d) → %'ld% m%n", iovlen, rc);
}
}
#endif