Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Seccomp filter example for x86 (32-bit and 64-bit) with BPF macros
0004  *
0005  * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
0006  * Author: Will Drewry <wad@chromium.org>
0007  *
0008  * The code may be used by anyone for any purpose,
0009  * and can serve as a starting point for developing
0010  * applications using prctl(PR_SET_SECCOMP, 2, ...).
0011  */
0012 #if defined(__i386__) || defined(__x86_64__)
0013 #define SUPPORTED_ARCH 1
0014 #endif
0015 
0016 #if defined(SUPPORTED_ARCH)
0017 #define __USE_GNU 1
0018 #define _GNU_SOURCE 1
0019 
0020 #include <linux/types.h>
0021 #include <linux/filter.h>
0022 #include <linux/seccomp.h>
0023 #include <linux/unistd.h>
0024 #include <signal.h>
0025 #include <stdio.h>
0026 #include <stddef.h>
0027 #include <string.h>
0028 #include <sys/prctl.h>
0029 #include <unistd.h>
0030 
0031 #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]))
0032 #define syscall_nr (offsetof(struct seccomp_data, nr))
0033 
0034 #if defined(__i386__)
0035 #define REG_RESULT  REG_EAX
0036 #define REG_SYSCALL REG_EAX
0037 #define REG_ARG0    REG_EBX
0038 #define REG_ARG1    REG_ECX
0039 #define REG_ARG2    REG_EDX
0040 #define REG_ARG3    REG_ESI
0041 #define REG_ARG4    REG_EDI
0042 #define REG_ARG5    REG_EBP
0043 #elif defined(__x86_64__)
0044 #define REG_RESULT  REG_RAX
0045 #define REG_SYSCALL REG_RAX
0046 #define REG_ARG0    REG_RDI
0047 #define REG_ARG1    REG_RSI
0048 #define REG_ARG2    REG_RDX
0049 #define REG_ARG3    REG_R10
0050 #define REG_ARG4    REG_R8
0051 #define REG_ARG5    REG_R9
0052 #endif
0053 
0054 #ifndef PR_SET_NO_NEW_PRIVS
0055 #define PR_SET_NO_NEW_PRIVS 38
0056 #endif
0057 
0058 #ifndef SYS_SECCOMP
0059 #define SYS_SECCOMP 1
0060 #endif
0061 
0062 static void emulator(int nr, siginfo_t *info, void *void_context)
0063 {
0064     ucontext_t *ctx = (ucontext_t *)(void_context);
0065     int syscall;
0066     char *buf;
0067     ssize_t bytes;
0068     size_t len;
0069     if (info->si_code != SYS_SECCOMP)
0070         return;
0071     if (!ctx)
0072         return;
0073     syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
0074     buf = (char *) ctx->uc_mcontext.gregs[REG_ARG1];
0075     len = (size_t) ctx->uc_mcontext.gregs[REG_ARG2];
0076 
0077     if (syscall != __NR_write)
0078         return;
0079     if (ctx->uc_mcontext.gregs[REG_ARG0] != STDERR_FILENO)
0080         return;
0081     /* Redirect stderr messages to stdout. Doesn't handle EINTR, etc */
0082     ctx->uc_mcontext.gregs[REG_RESULT] = -1;
0083     if (write(STDOUT_FILENO, "[ERR] ", 6) > 0) {
0084         bytes = write(STDOUT_FILENO, buf, len);
0085         ctx->uc_mcontext.gregs[REG_RESULT] = bytes;
0086     }
0087     return;
0088 }
0089 
0090 static int install_emulator(void)
0091 {
0092     struct sigaction act;
0093     sigset_t mask;
0094     memset(&act, 0, sizeof(act));
0095     sigemptyset(&mask);
0096     sigaddset(&mask, SIGSYS);
0097 
0098     act.sa_sigaction = &emulator;
0099     act.sa_flags = SA_SIGINFO;
0100     if (sigaction(SIGSYS, &act, NULL) < 0) {
0101         perror("sigaction");
0102         return -1;
0103     }
0104     if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
0105         perror("sigprocmask");
0106         return -1;
0107     }
0108     return 0;
0109 }
0110 
0111 static int install_filter(void)
0112 {
0113     struct sock_filter filter[] = {
0114         /* Grab the system call number */
0115         BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr),
0116         /* Jump table for the allowed syscalls */
0117         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_rt_sigreturn, 0, 1),
0118         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
0119 #ifdef __NR_sigreturn
0120         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_sigreturn, 0, 1),
0121         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
0122 #endif
0123         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit_group, 0, 1),
0124         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
0125         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit, 0, 1),
0126         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
0127         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_read, 1, 0),
0128         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_write, 3, 2),
0129 
0130         /* Check that read is only using stdin. */
0131         BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)),
0132         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDIN_FILENO, 4, 0),
0133         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
0134 
0135         /* Check that write is only using stdout */
0136         BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)),
0137         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDOUT_FILENO, 1, 0),
0138         /* Trap attempts to write to stderr */
0139         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDERR_FILENO, 1, 2),
0140 
0141         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
0142         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP),
0143         BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
0144     };
0145     struct sock_fprog prog = {
0146         .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
0147         .filter = filter,
0148     };
0149 
0150     if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
0151         perror("prctl(NO_NEW_PRIVS)");
0152         return 1;
0153     }
0154 
0155 
0156     if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
0157         perror("prctl");
0158         return 1;
0159     }
0160     return 0;
0161 }
0162 
0163 #define payload(_c) (_c), sizeof((_c))
0164 int main(int argc, char **argv)
0165 {
0166     char buf[4096];
0167     ssize_t bytes = 0;
0168     if (install_emulator())
0169         return 1;
0170     if (install_filter())
0171         return 1;
0172     syscall(__NR_write, STDOUT_FILENO,
0173         payload("OHAI! WHAT IS YOUR NAME? "));
0174     bytes = syscall(__NR_read, STDIN_FILENO, buf, sizeof(buf));
0175     syscall(__NR_write, STDOUT_FILENO, payload("HELLO, "));
0176     syscall(__NR_write, STDOUT_FILENO, buf, bytes);
0177     syscall(__NR_write, STDERR_FILENO,
0178         payload("Error message going to STDERR\n"));
0179     return 0;
0180 }
0181 #else   /* SUPPORTED_ARCH */
0182 /*
0183  * This sample is x86-only.  Since kernel samples are compiled with the
0184  * host toolchain, a non-x86 host will result in using only the main()
0185  * below.
0186  */
0187 int main(void)
0188 {
0189     return 1;
0190 }
0191 #endif  /* SUPPORTED_ARCH */