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