18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Seccomp filter example for x86 (32-bit and 64-bit) with BPF macros 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> 68c2ecf20Sopenharmony_ci * Author: Will Drewry <wad@chromium.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * The code may be used by anyone for any purpose, 98c2ecf20Sopenharmony_ci * and can serve as a starting point for developing 108c2ecf20Sopenharmony_ci * applications using prctl(PR_SET_SECCOMP, 2, ...). 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 138c2ecf20Sopenharmony_ci#define SUPPORTED_ARCH 1 148c2ecf20Sopenharmony_ci#endif 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#if defined(SUPPORTED_ARCH) 178c2ecf20Sopenharmony_ci#define __USE_GNU 1 188c2ecf20Sopenharmony_ci#define _GNU_SOURCE 1 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/filter.h> 228c2ecf20Sopenharmony_ci#include <linux/seccomp.h> 238c2ecf20Sopenharmony_ci#include <linux/unistd.h> 248c2ecf20Sopenharmony_ci#include <signal.h> 258c2ecf20Sopenharmony_ci#include <stdio.h> 268c2ecf20Sopenharmony_ci#include <stddef.h> 278c2ecf20Sopenharmony_ci#include <string.h> 288c2ecf20Sopenharmony_ci#include <sys/prctl.h> 298c2ecf20Sopenharmony_ci#include <unistd.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n])) 328c2ecf20Sopenharmony_ci#define syscall_nr (offsetof(struct seccomp_data, nr)) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#if defined(__i386__) 358c2ecf20Sopenharmony_ci#define REG_RESULT REG_EAX 368c2ecf20Sopenharmony_ci#define REG_SYSCALL REG_EAX 378c2ecf20Sopenharmony_ci#define REG_ARG0 REG_EBX 388c2ecf20Sopenharmony_ci#define REG_ARG1 REG_ECX 398c2ecf20Sopenharmony_ci#define REG_ARG2 REG_EDX 408c2ecf20Sopenharmony_ci#define REG_ARG3 REG_ESI 418c2ecf20Sopenharmony_ci#define REG_ARG4 REG_EDI 428c2ecf20Sopenharmony_ci#define REG_ARG5 REG_EBP 438c2ecf20Sopenharmony_ci#elif defined(__x86_64__) 448c2ecf20Sopenharmony_ci#define REG_RESULT REG_RAX 458c2ecf20Sopenharmony_ci#define REG_SYSCALL REG_RAX 468c2ecf20Sopenharmony_ci#define REG_ARG0 REG_RDI 478c2ecf20Sopenharmony_ci#define REG_ARG1 REG_RSI 488c2ecf20Sopenharmony_ci#define REG_ARG2 REG_RDX 498c2ecf20Sopenharmony_ci#define REG_ARG3 REG_R10 508c2ecf20Sopenharmony_ci#define REG_ARG4 REG_R8 518c2ecf20Sopenharmony_ci#define REG_ARG5 REG_R9 528c2ecf20Sopenharmony_ci#endif 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#ifndef PR_SET_NO_NEW_PRIVS 558c2ecf20Sopenharmony_ci#define PR_SET_NO_NEW_PRIVS 38 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#ifndef SYS_SECCOMP 598c2ecf20Sopenharmony_ci#define SYS_SECCOMP 1 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void emulator(int nr, siginfo_t *info, void *void_context) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci ucontext_t *ctx = (ucontext_t *)(void_context); 658c2ecf20Sopenharmony_ci int syscall; 668c2ecf20Sopenharmony_ci char *buf; 678c2ecf20Sopenharmony_ci ssize_t bytes; 688c2ecf20Sopenharmony_ci size_t len; 698c2ecf20Sopenharmony_ci if (info->si_code != SYS_SECCOMP) 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci if (!ctx) 728c2ecf20Sopenharmony_ci return; 738c2ecf20Sopenharmony_ci syscall = ctx->uc_mcontext.gregs[REG_SYSCALL]; 748c2ecf20Sopenharmony_ci buf = (char *) ctx->uc_mcontext.gregs[REG_ARG1]; 758c2ecf20Sopenharmony_ci len = (size_t) ctx->uc_mcontext.gregs[REG_ARG2]; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (syscall != __NR_write) 788c2ecf20Sopenharmony_ci return; 798c2ecf20Sopenharmony_ci if (ctx->uc_mcontext.gregs[REG_ARG0] != STDERR_FILENO) 808c2ecf20Sopenharmony_ci return; 818c2ecf20Sopenharmony_ci /* Redirect stderr messages to stdout. Doesn't handle EINTR, etc */ 828c2ecf20Sopenharmony_ci ctx->uc_mcontext.gregs[REG_RESULT] = -1; 838c2ecf20Sopenharmony_ci if (write(STDOUT_FILENO, "[ERR] ", 6) > 0) { 848c2ecf20Sopenharmony_ci bytes = write(STDOUT_FILENO, buf, len); 858c2ecf20Sopenharmony_ci ctx->uc_mcontext.gregs[REG_RESULT] = bytes; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int install_emulator(void) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct sigaction act; 938c2ecf20Sopenharmony_ci sigset_t mask; 948c2ecf20Sopenharmony_ci memset(&act, 0, sizeof(act)); 958c2ecf20Sopenharmony_ci sigemptyset(&mask); 968c2ecf20Sopenharmony_ci sigaddset(&mask, SIGSYS); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci act.sa_sigaction = &emulator; 998c2ecf20Sopenharmony_ci act.sa_flags = SA_SIGINFO; 1008c2ecf20Sopenharmony_ci if (sigaction(SIGSYS, &act, NULL) < 0) { 1018c2ecf20Sopenharmony_ci perror("sigaction"); 1028c2ecf20Sopenharmony_ci return -1; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) { 1058c2ecf20Sopenharmony_ci perror("sigprocmask"); 1068c2ecf20Sopenharmony_ci return -1; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int install_filter(void) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct sock_filter filter[] = { 1148c2ecf20Sopenharmony_ci /* Grab the system call number */ 1158c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr), 1168c2ecf20Sopenharmony_ci /* Jump table for the allowed syscalls */ 1178c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_rt_sigreturn, 0, 1), 1188c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), 1198c2ecf20Sopenharmony_ci#ifdef __NR_sigreturn 1208c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_sigreturn, 0, 1), 1218c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit_group, 0, 1), 1248c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), 1258c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit, 0, 1), 1268c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), 1278c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_read, 1, 0), 1288c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_write, 3, 2), 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Check that read is only using stdin. */ 1318c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)), 1328c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDIN_FILENO, 4, 0), 1338c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Check that write is only using stdout */ 1368c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)), 1378c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDOUT_FILENO, 1, 0), 1388c2ecf20Sopenharmony_ci /* Trap attempts to write to stderr */ 1398c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDERR_FILENO, 1, 2), 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), 1428c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP), 1438c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), 1448c2ecf20Sopenharmony_ci }; 1458c2ecf20Sopenharmony_ci struct sock_fprog prog = { 1468c2ecf20Sopenharmony_ci .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), 1478c2ecf20Sopenharmony_ci .filter = filter, 1488c2ecf20Sopenharmony_ci }; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1518c2ecf20Sopenharmony_ci perror("prctl(NO_NEW_PRIVS)"); 1528c2ecf20Sopenharmony_ci return 1; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 1578c2ecf20Sopenharmony_ci perror("prctl"); 1588c2ecf20Sopenharmony_ci return 1; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#define payload(_c) (_c), sizeof((_c)) 1648c2ecf20Sopenharmony_ciint main(int argc, char **argv) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci char buf[4096]; 1678c2ecf20Sopenharmony_ci ssize_t bytes = 0; 1688c2ecf20Sopenharmony_ci if (install_emulator()) 1698c2ecf20Sopenharmony_ci return 1; 1708c2ecf20Sopenharmony_ci if (install_filter()) 1718c2ecf20Sopenharmony_ci return 1; 1728c2ecf20Sopenharmony_ci syscall(__NR_write, STDOUT_FILENO, 1738c2ecf20Sopenharmony_ci payload("OHAI! WHAT IS YOUR NAME? ")); 1748c2ecf20Sopenharmony_ci bytes = syscall(__NR_read, STDIN_FILENO, buf, sizeof(buf)); 1758c2ecf20Sopenharmony_ci syscall(__NR_write, STDOUT_FILENO, payload("HELLO, ")); 1768c2ecf20Sopenharmony_ci syscall(__NR_write, STDOUT_FILENO, buf, bytes); 1778c2ecf20Sopenharmony_ci syscall(__NR_write, STDERR_FILENO, 1788c2ecf20Sopenharmony_ci payload("Error message going to STDERR\n")); 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci#else /* SUPPORTED_ARCH */ 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * This sample is x86-only. Since kernel samples are compiled with the 1848c2ecf20Sopenharmony_ci * host toolchain, a non-x86 host will result in using only the main() 1858c2ecf20Sopenharmony_ci * below. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ciint main(void) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return 1; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci#endif /* SUPPORTED_ARCH */ 192