1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Naive system call dropper built on seccomp_filter. |
4 | * |
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 developing |
10 | * applications using prctl(PR_SET_SECCOMP, 2, ...). |
11 | * |
12 | * When run, returns the specified errno for the specified |
13 | * system call number against the given architecture. |
14 | * |
15 | */ |
16 | |
17 | #include <errno.h> |
18 | #include <linux/audit.h> |
19 | #include <linux/filter.h> |
20 | #include <linux/seccomp.h> |
21 | #include <linux/unistd.h> |
22 | #include <stdio.h> |
23 | #include <stddef.h> |
24 | #include <stdlib.h> |
25 | #include <sys/prctl.h> |
26 | #include <unistd.h> |
27 | |
28 | static int install_filter(int arch, int nr, int error) |
29 | { |
30 | struct sock_filter filter[] = { |
31 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, |
32 | (offsetof(struct seccomp_data, arch))), |
33 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, arch, 0, 3), |
34 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, |
35 | (offsetof(struct seccomp_data, nr))), |
36 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), |
37 | BPF_STMT(BPF_RET+BPF_K, |
38 | SECCOMP_RET_ERRNO|(error & SECCOMP_RET_DATA)), |
39 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), |
40 | }; |
41 | struct sock_fprog prog = { |
42 | .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), |
43 | .filter = filter, |
44 | }; |
45 | if (error == -1) { |
46 | struct sock_filter kill = BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL); |
47 | filter[4] = kill; |
48 | } |
49 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
50 | perror(s: "prctl(NO_NEW_PRIVS)" ); |
51 | return 1; |
52 | } |
53 | if (prctl(PR_SET_SECCOMP, 2, &prog)) { |
54 | perror(s: "prctl(PR_SET_SECCOMP)" ); |
55 | return 1; |
56 | } |
57 | return 0; |
58 | } |
59 | |
60 | int main(int argc, char **argv) |
61 | { |
62 | if (argc < 5) { |
63 | fprintf(stderr, format: "Usage:\n" |
64 | "dropper <arch> <syscall_nr> <errno> <prog> [<args>]\n" |
65 | "Hint: AUDIT_ARCH_I386: 0x%X\n" |
66 | " AUDIT_ARCH_X86_64: 0x%X\n" |
67 | " errno == -1 means SECCOMP_RET_KILL\n" |
68 | "\n" , AUDIT_ARCH_I386, AUDIT_ARCH_X86_64); |
69 | return 1; |
70 | } |
71 | if (install_filter(arch: strtol(nptr: argv[1], NULL, base: 0), nr: strtol(nptr: argv[2], NULL, base: 0), |
72 | error: strtol(nptr: argv[3], NULL, base: 0))) |
73 | return 1; |
74 | execv(path: argv[4], argv: &argv[4]); |
75 | printf(format: "Failed to execv\n" ); |
76 | return 255; |
77 | } |
78 | |