1 /*
2 * Check verbose decoding of prctl PR_SET_SECCOMP SECCOMP_MODE_FILTER.
3 *
4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2016-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include <stddef.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <errno.h>
16 #include <sys/prctl.h>
17 #include <linux/seccomp.h>
18 #include <linux/filter.h>
19 #include "scno.h"
20
21 #if defined BPF_JUMP && defined BPF_STMT
22
23 # define SOCK_FILTER_ALLOW_SYSCALL(nr) \
24 BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, __NR_ ## nr, 0, 1), \
25 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)
26
27 # define SOCK_FILTER_DENY_SYSCALL(nr, err) \
28 BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, __NR_ ## nr, 0, 1), \
29 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|(SECCOMP_RET_DATA & (err)))
30
31 # define SOCK_FILTER_KILL_PROCESS \
32 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL)
33
34 # define PRINT_ALLOW_SYSCALL(nr) \
35 printf("BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#lx, 0, 0x1), " \
36 "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), ", \
37 (long) __NR_ ## nr)
38
39 # define PRINT_DENY_SYSCALL(nr, err) \
40 printf("BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#lx, 0, 0x1), " \
41 "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|%#x), ", \
42 (long) __NR_ ## nr, err)
43
44 static const struct sock_filter filter[] = {
45 /* load syscall number */
46 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)),
47
48 /* allow syscalls */
49 SOCK_FILTER_ALLOW_SYSCALL(close),
50 SOCK_FILTER_ALLOW_SYSCALL(exit),
51 SOCK_FILTER_ALLOW_SYSCALL(exit_group),
52
53 /* deny syscalls */
54 SOCK_FILTER_DENY_SYSCALL(sync, EBUSY),
55 SOCK_FILTER_DENY_SYSCALL(setsid, EPERM),
56
57 /* kill process */
58 SOCK_FILTER_KILL_PROCESS
59 };
60
61 static const struct sock_fprog prog = {
62 .len = ARRAY_SIZE(filter),
63 .filter = (struct sock_filter *) filter,
64 };
65
66 int
67 main(void)
68 {
69 int fds[2];
70
71 prctl_marker();
72
73 puts("prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) = 0");
74
75 printf("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, {len=%u, filter=[",
76 prog.len);
77
78 printf("BPF_STMT(BPF_LD|BPF_W|BPF_ABS, %#x), ",
79 (unsigned) offsetof(struct seccomp_data, nr));
80
81 PRINT_ALLOW_SYSCALL(close);
82 PRINT_ALLOW_SYSCALL(exit);
83 PRINT_ALLOW_SYSCALL(exit_group);
84
85 PRINT_DENY_SYSCALL(sync, EBUSY),
86 PRINT_DENY_SYSCALL(setsid, EPERM),
87
88 printf("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD)");
89
90 puts("]}) = 0");
91 puts("+++ exited with 0 +++");
92
93 fflush(stdout);
94 close(0);
95 close(1);
96
97 if (pipe(fds))
98 perror_msg_and_fail("pipe");
99 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
100 perror_msg_and_skip("PR_SET_NO_NEW_PRIVS");
101 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
102 perror_msg_and_skip("PR_SET_SECCOMP");
103 if (close(0) || close(1))
104 _exit(77);
105
106 _exit(0);
107 }
108
109 #else
110
111 SKIP_MAIN_UNDEFINED("BPF_JUMP && BPF_STMT")
112
113 #endif