#include "c.h"
#include "exitcodes.h"
#include "nls.h"
+#include "bitops.h"
#if __x86_64__
# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_X86_64
#endif
#define UL_BPF_NOP (struct sock_filter) BPF_JUMP(BPF_JMP | BPF_JA, 0, 0, 0)
+#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define syscall_nr (offsetof(struct seccomp_data, nr))
#define syscall_arch (offsetof(struct seccomp_data, arch))
+#define syscall_arg(n) (offsetof(struct seccomp_data, args[n]))
struct syscall {
const char *const name;
if (optind >= argc)
errtryhelp(EXIT_FAILURE);
-#define N_FILTERS (ARRAY_SIZE(syscalls) * 2 + 5)
+#define N_FILTERS (ARRAY_SIZE(syscalls) * 2 + 12)
struct sock_filter filter[N_FILTERS] = {
- [0] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arch),
- [1] = BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECCOMP_ARCH_NATIVE, 1, 0),
- [2] = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP),
- [3] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_nr),
+ [0] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arch),
+ [1] = BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECCOMP_ARCH_NATIVE, 1, 0),
+ [2] = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP),
+
+ /* Blocking "execve" normally would also block our own call to
+ * it and the end of main. To distinguish between our execve
+ * and the execve to be blocked, compare the environ pointer.
+ *
+ * See https://lore.kernel.org/all/CAAnLoWnS74dK9Wq4EQ-uzQ0qCRfSK-dLqh+HCais-5qwDjrVzg@mail.gmail.com/
+ */
+ [3] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_nr),
+ [4] = BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 0, 5),
+ [5] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arg(2) + 4 * !IS_LITTLE_ENDIAN),
+ [6] = BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uint64_t)(uintptr_t) environ, 0, 3),
+ [7] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arg(2) + 4 * IS_LITTLE_ENDIAN),
+ [8] = BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uint64_t)(uintptr_t) environ >> 32, 0, 1),
+ [9] = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
+
+ [10] = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_nr),
[N_FILTERS - 1] = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
};
static_assert(ARRAY_SIZE(filter) <= BPF_MAXINSNS, "bpf filter too big");
for (i = 0; i < ARRAY_SIZE(syscalls); i++) {
- struct sock_filter *f = &filter[4 + i * 2];
+ struct sock_filter *f = &filter[11 + i * 2];
*f = (struct sock_filter) BPF_JUMP(
BPF_JMP | BPF_JEQ | BPF_K,