^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Seccomp filter example for x86 (32-bit and 64-bit) with BPF macros
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Will Drewry <wad@chromium.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * The code may be used by anyone for any purpose,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and can serve as a starting point for developing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * applications using prctl(PR_SET_SECCOMP, 2, ...).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #if defined(__i386__) || defined(__x86_64__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define SUPPORTED_ARCH 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #if defined(SUPPORTED_ARCH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define __USE_GNU 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define _GNU_SOURCE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/filter.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/seccomp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <sys/prctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define syscall_nr (offsetof(struct seccomp_data, nr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #if defined(__i386__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define REG_RESULT REG_EAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define REG_SYSCALL REG_EAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define REG_ARG0 REG_EBX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define REG_ARG1 REG_ECX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define REG_ARG2 REG_EDX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define REG_ARG3 REG_ESI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define REG_ARG4 REG_EDI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define REG_ARG5 REG_EBP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #elif defined(__x86_64__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define REG_RESULT REG_RAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define REG_SYSCALL REG_RAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define REG_ARG0 REG_RDI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define REG_ARG1 REG_RSI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define REG_ARG2 REG_RDX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define REG_ARG3 REG_R10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define REG_ARG4 REG_R8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define REG_ARG5 REG_R9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #ifndef PR_SET_NO_NEW_PRIVS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define PR_SET_NO_NEW_PRIVS 38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #ifndef SYS_SECCOMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define SYS_SECCOMP 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static void emulator(int nr, siginfo_t *info, void *void_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ucontext_t *ctx = (ucontext_t *)(void_context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int syscall;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) ssize_t bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (info->si_code != SYS_SECCOMP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) buf = (char *) ctx->uc_mcontext.gregs[REG_ARG1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) len = (size_t) ctx->uc_mcontext.gregs[REG_ARG2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (syscall != __NR_write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (ctx->uc_mcontext.gregs[REG_ARG0] != STDERR_FILENO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Redirect stderr messages to stdout. Doesn't handle EINTR, etc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ctx->uc_mcontext.gregs[REG_RESULT] = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (write(STDOUT_FILENO, "[ERR] ", 6) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) bytes = write(STDOUT_FILENO, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ctx->uc_mcontext.gregs[REG_RESULT] = bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int install_emulator(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct sigaction act;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) sigset_t mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) memset(&act, 0, sizeof(act));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) sigemptyset(&mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) sigaddset(&mask, SIGSYS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) act.sa_sigaction = &emulator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) act.sa_flags = SA_SIGINFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (sigaction(SIGSYS, &act, NULL) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) perror("sigaction");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) perror("sigprocmask");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int install_filter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct sock_filter filter[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Grab the system call number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Jump table for the allowed syscalls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_rt_sigreturn, 0, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #ifdef __NR_sigreturn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_sigreturn, 0, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit_group, 0, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit, 0, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_read, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_write, 3, 2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* Check that read is only using stdin. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDIN_FILENO, 4, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /* Check that write is only using stdout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDOUT_FILENO, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Trap attempts to write to stderr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDERR_FILENO, 1, 2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct sock_fprog prog = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .filter = filter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) perror("prctl(NO_NEW_PRIVS)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) perror("prctl");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define payload(_c) (_c), sizeof((_c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) char buf[4096];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ssize_t bytes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (install_emulator())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (install_filter())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) syscall(__NR_write, STDOUT_FILENO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) payload("OHAI! WHAT IS YOUR NAME? "));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) bytes = syscall(__NR_read, STDIN_FILENO, buf, sizeof(buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) syscall(__NR_write, STDOUT_FILENO, payload("HELLO, "));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) syscall(__NR_write, STDOUT_FILENO, buf, bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) syscall(__NR_write, STDERR_FILENO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) payload("Error message going to STDERR\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) #else /* SUPPORTED_ARCH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * This sample is x86-only. Since kernel samples are compiled with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * host toolchain, a non-x86 host will result in using only the main()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int main(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) #endif /* SUPPORTED_ARCH */