brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · c09e4a1 Raw
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