]> granicus.if.org Git - strace/blob - tests/prctl-seccomp-filter-v.c
9efc015604c2e045b66371ba02b3e13da390d7e1
[strace] / tests / prctl-seccomp-filter-v.c
1 /*
2  * Check verbose decoding of prctl PR_SET_SECCOMP SECCOMP_MODE_FILTER.
3  *
4  * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016-2017 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 <asm/unistd.h>
17
18 #ifdef HAVE_PRCTL
19 # include <sys/prctl.h>
20 #endif
21 #ifdef HAVE_LINUX_SECCOMP_H
22 # include <linux/seccomp.h>
23 #endif
24 #include <linux/filter.h>
25
26 #if defined HAVE_PRCTL \
27  && defined PR_SET_NO_NEW_PRIVS \
28  && defined PR_SET_SECCOMP \
29  && defined SECCOMP_MODE_FILTER \
30  && defined SECCOMP_RET_ERRNO \
31  && defined BPF_JUMP \
32  && defined BPF_STMT
33
34 #define SOCK_FILTER_ALLOW_SYSCALL(nr) \
35                 BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, __NR_ ## nr, 0, 1), \
36                 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)
37
38 #define SOCK_FILTER_DENY_SYSCALL(nr, err) \
39                 BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, __NR_ ## nr, 0, 1), \
40                 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|(SECCOMP_RET_DATA & (err)))
41
42 #define SOCK_FILTER_KILL_PROCESS \
43                 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL)
44
45 #define PRINT_ALLOW_SYSCALL(nr) \
46         printf("BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#x, 0, 0x1), " \
47                "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), ", \
48                __NR_ ## nr)
49
50 #define PRINT_DENY_SYSCALL(nr, err) \
51         printf("BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#x, 0, 0x1), " \
52                "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|%#x), ", \
53                __NR_ ## nr, err)
54
55 static const struct sock_filter filter[] = {
56         /* load syscall number */
57         BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)),
58
59         /* allow syscalls */
60         SOCK_FILTER_ALLOW_SYSCALL(close),
61         SOCK_FILTER_ALLOW_SYSCALL(exit),
62         SOCK_FILTER_ALLOW_SYSCALL(exit_group),
63
64         /* deny syscalls */
65         SOCK_FILTER_DENY_SYSCALL(sync, EBUSY),
66         SOCK_FILTER_DENY_SYSCALL(setsid, EPERM),
67
68         /* kill process */
69         SOCK_FILTER_KILL_PROCESS
70 };
71
72 static const struct sock_fprog prog = {
73         .len = ARRAY_SIZE(filter),
74         .filter = (struct sock_filter *) filter,
75 };
76
77 int
78 main(void)
79 {
80         int fds[2];
81
82         puts("prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)  = 0");
83
84         printf("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, {len=%u, filter=[",
85                prog.len);
86
87         printf("BPF_STMT(BPF_LD|BPF_W|BPF_ABS, %#x), ",
88                (unsigned) offsetof(struct seccomp_data, nr));
89
90         PRINT_ALLOW_SYSCALL(close);
91         PRINT_ALLOW_SYSCALL(exit);
92         PRINT_ALLOW_SYSCALL(exit_group);
93
94         PRINT_DENY_SYSCALL(sync, EBUSY),
95         PRINT_DENY_SYSCALL(setsid, EPERM),
96
97         printf("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD)");
98
99         puts("]}) = 0");
100         puts("+++ exited with 0 +++");
101
102         fflush(stdout);
103         close(0);
104         close(1);
105
106         if (pipe(fds))
107                 perror_msg_and_fail("pipe");
108         if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
109                 perror_msg_and_skip("PR_SET_NO_NEW_PRIVS");
110         if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
111                 perror_msg_and_skip("PR_SET_SECCOMP");
112         if (close(0) || close(1))
113                 _exit(77);
114
115         _exit(0);
116 }
117
118 #else
119
120 SKIP_MAIN_UNDEFINED("HAVE_PRCTL && PR_SET_NO_NEW_PRIVS && PR_SET_SECCOMP"
121                     " && SECCOMP_MODE_FILTER && SECCOMP_RET_ERRNO"
122                     " && BPF_JUMP && BPF_STMT")
123
124 #endif