1e500db3fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c99ee51aSKees Cook /*
3c99ee51aSKees Cook  * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
4c99ee51aSKees Cook  *
5c99ee51aSKees Cook  * Test code for seccomp bpf.
6c99ee51aSKees Cook  */
7c99ee51aSKees Cook 
86a21cc50STycho Andersen #define _GNU_SOURCE
90ce105bfSMatt Redfearn #include <sys/types.h>
1010859f38SKees Cook 
1110859f38SKees Cook /*
1210859f38SKees Cook  * glibc 2.26 and later have SIGSYS in siginfo_t. Before that,
1310859f38SKees Cook  * we need to use the kernel's siginfo.h file and trick glibc
1410859f38SKees Cook  * into accepting it.
1510859f38SKees Cook  */
1610859f38SKees Cook #if !__GLIBC_PREREQ(2, 26)
17c99ee51aSKees Cook # include <asm/siginfo.h>
18c99ee51aSKees Cook # define __have_siginfo_t 1
19c99ee51aSKees Cook # define __have_sigval_t 1
20c99ee51aSKees Cook # define __have_sigevent_t 1
2110859f38SKees Cook #endif
22c99ee51aSKees Cook 
23c99ee51aSKees Cook #include <errno.h>
24c99ee51aSKees Cook #include <linux/filter.h>
25c99ee51aSKees Cook #include <sys/prctl.h>
26c99ee51aSKees Cook #include <sys/ptrace.h>
27c99ee51aSKees Cook #include <sys/user.h>
28c99ee51aSKees Cook #include <linux/prctl.h>
29c99ee51aSKees Cook #include <linux/ptrace.h>
30c99ee51aSKees Cook #include <linux/seccomp.h>
31c99ee51aSKees Cook #include <pthread.h>
32c99ee51aSKees Cook #include <semaphore.h>
33c99ee51aSKees Cook #include <signal.h>
34c99ee51aSKees Cook #include <stddef.h>
35c99ee51aSKees Cook #include <stdbool.h>
36c99ee51aSKees Cook #include <string.h>
37256d0afbSKees Cook #include <time.h>
38223e660bSChristian Brauner #include <limits.h>
39c99ee51aSKees Cook #include <linux/elf.h>
40c99ee51aSKees Cook #include <sys/uio.h>
41256d0afbSKees Cook #include <sys/utsname.h>
42fd88d16cSRobert Sesek #include <sys/fcntl.h>
43fd88d16cSRobert Sesek #include <sys/mman.h>
44fd88d16cSRobert Sesek #include <sys/times.h>
456a21cc50STycho Andersen #include <sys/socket.h>
466a21cc50STycho Andersen #include <sys/ioctl.h>
470eebfed2SChristian Brauner #include <linux/kcmp.h>
48c97aedc5SSargun Dhillon #include <sys/resource.h>
49d250a3e4SJann Horn #include <sys/capability.h>
50c99ee51aSKees Cook 
51c99ee51aSKees Cook #include <unistd.h>
52c99ee51aSKees Cook #include <sys/syscall.h>
536a21cc50STycho Andersen #include <poll.h>
54c99ee51aSKees Cook 
550b40808aSMickaël Salaün #include "../kselftest_harness.h"
56ad568218SChristian Brauner #include "../clone3/clone3_selftests.h"
57c99ee51aSKees Cook 
588b1bc88cSKees Cook /* Attempt to de-conflict with the selftests tree. */
598b1bc88cSKees Cook #ifndef SKIP
608b1bc88cSKees Cook #define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
618b1bc88cSKees Cook #endif
62c99ee51aSKees Cook 
633b96a9c5SSargun Dhillon #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
643b96a9c5SSargun Dhillon 
65c99ee51aSKees Cook #ifndef PR_SET_PTRACER
66c99ee51aSKees Cook # define PR_SET_PTRACER 0x59616d61
67c99ee51aSKees Cook #endif
68c99ee51aSKees Cook 
69c99ee51aSKees Cook #ifndef PR_SET_NO_NEW_PRIVS
70c99ee51aSKees Cook #define PR_SET_NO_NEW_PRIVS 38
71c99ee51aSKees Cook #define PR_GET_NO_NEW_PRIVS 39
72c99ee51aSKees Cook #endif
73c99ee51aSKees Cook 
74c99ee51aSKees Cook #ifndef PR_SECCOMP_EXT
75c99ee51aSKees Cook #define PR_SECCOMP_EXT 43
76c99ee51aSKees Cook #endif
77c99ee51aSKees Cook 
78c99ee51aSKees Cook #ifndef SECCOMP_EXT_ACT
79c99ee51aSKees Cook #define SECCOMP_EXT_ACT 1
80c99ee51aSKees Cook #endif
81c99ee51aSKees Cook 
82c99ee51aSKees Cook #ifndef SECCOMP_EXT_ACT_TSYNC
83c99ee51aSKees Cook #define SECCOMP_EXT_ACT_TSYNC 1
84c99ee51aSKees Cook #endif
85c99ee51aSKees Cook 
86c99ee51aSKees Cook #ifndef SECCOMP_MODE_STRICT
87c99ee51aSKees Cook #define SECCOMP_MODE_STRICT 1
88c99ee51aSKees Cook #endif
89c99ee51aSKees Cook 
90c99ee51aSKees Cook #ifndef SECCOMP_MODE_FILTER
91c99ee51aSKees Cook #define SECCOMP_MODE_FILTER 2
92c99ee51aSKees Cook #endif
93c99ee51aSKees Cook 
94f3e1821dSKees Cook #ifndef SECCOMP_RET_ALLOW
95c99ee51aSKees Cook struct seccomp_data {
96c99ee51aSKees Cook 	int nr;
97c99ee51aSKees Cook 	__u32 arch;
98c99ee51aSKees Cook 	__u64 instruction_pointer;
99c99ee51aSKees Cook 	__u64 args[6];
100c99ee51aSKees Cook };
101c99ee51aSKees Cook #endif
102c99ee51aSKees Cook 
103f3e1821dSKees Cook #ifndef SECCOMP_RET_KILL_PROCESS
104f3e1821dSKees Cook #define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */
105fd76875cSKees Cook #define SECCOMP_RET_KILL_THREAD	 0x00000000U /* kill the thread */
106fd76875cSKees Cook #endif
107c99ee51aSKees Cook #ifndef SECCOMP_RET_KILL
108fd76875cSKees Cook #define SECCOMP_RET_KILL	 SECCOMP_RET_KILL_THREAD
109c99ee51aSKees Cook #define SECCOMP_RET_TRAP	 0x00030000U /* disallow and force a SIGSYS */
110c99ee51aSKees Cook #define SECCOMP_RET_ERRNO	 0x00050000U /* returns an errno */
111c99ee51aSKees Cook #define SECCOMP_RET_TRACE	 0x7ff00000U /* pass to a tracer or disallow */
112c99ee51aSKees Cook #define SECCOMP_RET_ALLOW	 0x7fff0000U /* allow */
11359f5cf44STyler Hicks #endif
11459f5cf44STyler Hicks #ifndef SECCOMP_RET_LOG
11559f5cf44STyler Hicks #define SECCOMP_RET_LOG		 0x7ffc0000U /* allow after logging */
11659f5cf44STyler Hicks #endif
117c99ee51aSKees Cook 
118f3e1821dSKees Cook #ifndef __NR_seccomp
119f3e1821dSKees Cook # if defined(__i386__)
120f3e1821dSKees Cook #  define __NR_seccomp 354
121f3e1821dSKees Cook # elif defined(__x86_64__)
122f3e1821dSKees Cook #  define __NR_seccomp 317
123f3e1821dSKees Cook # elif defined(__arm__)
124f3e1821dSKees Cook #  define __NR_seccomp 383
125f3e1821dSKees Cook # elif defined(__aarch64__)
126f3e1821dSKees Cook #  define __NR_seccomp 277
1275340627eSDavid Abdurachmanov # elif defined(__riscv)
1285340627eSDavid Abdurachmanov #  define __NR_seccomp 277
129e95a4f8cSGuo Ren # elif defined(__csky__)
130e95a4f8cSGuo Ren #  define __NR_seccomp 277
131eb4071b9SHuacai Chen # elif defined(__loongarch__)
132eb4071b9SHuacai Chen #  define __NR_seccomp 277
133f3e1821dSKees Cook # elif defined(__hppa__)
134f3e1821dSKees Cook #  define __NR_seccomp 338
135f3e1821dSKees Cook # elif defined(__powerpc__)
136f3e1821dSKees Cook #  define __NR_seccomp 358
137f3e1821dSKees Cook # elif defined(__s390__)
138f3e1821dSKees Cook #  define __NR_seccomp 348
139768877beSMax Filippov # elif defined(__xtensa__)
140768877beSMax Filippov #  define __NR_seccomp 337
1410bb605c2SMichael Karcher # elif defined(__sh__)
1420bb605c2SMichael Karcher #  define __NR_seccomp 372
143be6c50d3SMichael Schmitz # elif defined(__mc68000__)
144be6c50d3SMichael Schmitz #  define __NR_seccomp 380
145f3e1821dSKees Cook # else
146f3e1821dSKees Cook #  warning "seccomp syscall number unknown for this architecture"
147f3e1821dSKees Cook #  define __NR_seccomp 0xffff
148f3e1821dSKees Cook # endif
149f3e1821dSKees Cook #endif
150c99ee51aSKees Cook 
151f3e1821dSKees Cook #ifndef SECCOMP_SET_MODE_STRICT
152f3e1821dSKees Cook #define SECCOMP_SET_MODE_STRICT 0
153f3e1821dSKees Cook #endif
154f3e1821dSKees Cook 
155f3e1821dSKees Cook #ifndef SECCOMP_SET_MODE_FILTER
156f3e1821dSKees Cook #define SECCOMP_SET_MODE_FILTER 1
157f3e1821dSKees Cook #endif
158f3e1821dSKees Cook 
159f3e1821dSKees Cook #ifndef SECCOMP_GET_ACTION_AVAIL
160f3e1821dSKees Cook #define SECCOMP_GET_ACTION_AVAIL 2
161f3e1821dSKees Cook #endif
162f3e1821dSKees Cook 
1636a21cc50STycho Andersen #ifndef SECCOMP_GET_NOTIF_SIZES
1646a21cc50STycho Andersen #define SECCOMP_GET_NOTIF_SIZES 3
1656a21cc50STycho Andersen #endif
1666a21cc50STycho Andersen 
167f3e1821dSKees Cook #ifndef SECCOMP_FILTER_FLAG_TSYNC
16800a02d0cSKees Cook #define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
169f3e1821dSKees Cook #endif
170f3e1821dSKees Cook 
171f3e1821dSKees Cook #ifndef SECCOMP_FILTER_FLAG_LOG
17200a02d0cSKees Cook #define SECCOMP_FILTER_FLAG_LOG (1UL << 1)
17300a02d0cSKees Cook #endif
17400a02d0cSKees Cook 
17500a02d0cSKees Cook #ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW
17600a02d0cSKees Cook #define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
177f3e1821dSKees Cook #endif
178f3e1821dSKees Cook 
179d057dc4eSTycho Andersen #ifndef PTRACE_SECCOMP_GET_METADATA
180d057dc4eSTycho Andersen #define PTRACE_SECCOMP_GET_METADATA	0x420d
181d057dc4eSTycho Andersen 
182d057dc4eSTycho Andersen struct seccomp_metadata {
183d057dc4eSTycho Andersen 	__u64 filter_off;       /* Input: which filter */
184d057dc4eSTycho Andersen 	__u64 flags;             /* Output: filter's flags */
185d057dc4eSTycho Andersen };
186d057dc4eSTycho Andersen #endif
187d057dc4eSTycho Andersen 
1886a21cc50STycho Andersen #ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
1896a21cc50STycho Andersen #define SECCOMP_FILTER_FLAG_NEW_LISTENER	(1UL << 3)
190c97aedc5SSargun Dhillon #endif
1916a21cc50STycho Andersen 
192c97aedc5SSargun Dhillon #ifndef SECCOMP_RET_USER_NOTIF
1936a21cc50STycho Andersen #define SECCOMP_RET_USER_NOTIF 0x7fc00000U
1946a21cc50STycho Andersen 
1956a21cc50STycho Andersen #define SECCOMP_IOC_MAGIC		'!'
1966a21cc50STycho Andersen #define SECCOMP_IO(nr)			_IO(SECCOMP_IOC_MAGIC, nr)
1976a21cc50STycho Andersen #define SECCOMP_IOR(nr, type)		_IOR(SECCOMP_IOC_MAGIC, nr, type)
1986a21cc50STycho Andersen #define SECCOMP_IOW(nr, type)		_IOW(SECCOMP_IOC_MAGIC, nr, type)
1996a21cc50STycho Andersen #define SECCOMP_IOWR(nr, type)		_IOWR(SECCOMP_IOC_MAGIC, nr, type)
2006a21cc50STycho Andersen 
2016a21cc50STycho Andersen /* Flags for seccomp notification fd ioctl. */
2026a21cc50STycho Andersen #define SECCOMP_IOCTL_NOTIF_RECV	SECCOMP_IOWR(0, struct seccomp_notif)
2036a21cc50STycho Andersen #define SECCOMP_IOCTL_NOTIF_SEND	SECCOMP_IOWR(1,	\
2046a21cc50STycho Andersen 						struct seccomp_notif_resp)
20547e33c05SKees Cook #define SECCOMP_IOCTL_NOTIF_ID_VALID	SECCOMP_IOW(2, __u64)
2066a21cc50STycho Andersen 
2076a21cc50STycho Andersen struct seccomp_notif {
2086a21cc50STycho Andersen 	__u64 id;
2096a21cc50STycho Andersen 	__u32 pid;
2106a21cc50STycho Andersen 	__u32 flags;
2116a21cc50STycho Andersen 	struct seccomp_data data;
2126a21cc50STycho Andersen };
2136a21cc50STycho Andersen 
2146a21cc50STycho Andersen struct seccomp_notif_resp {
2156a21cc50STycho Andersen 	__u64 id;
2166a21cc50STycho Andersen 	__s64 val;
2176a21cc50STycho Andersen 	__s32 error;
2186a21cc50STycho Andersen 	__u32 flags;
2196a21cc50STycho Andersen };
2206a21cc50STycho Andersen 
2216a21cc50STycho Andersen struct seccomp_notif_sizes {
2226a21cc50STycho Andersen 	__u16 seccomp_notif;
2236a21cc50STycho Andersen 	__u16 seccomp_notif_resp;
2246a21cc50STycho Andersen 	__u16 seccomp_data;
2256a21cc50STycho Andersen };
2266a21cc50STycho Andersen #endif
2276a21cc50STycho Andersen 
228c97aedc5SSargun Dhillon #ifndef SECCOMP_IOCTL_NOTIF_ADDFD
229c97aedc5SSargun Dhillon /* On success, the return value is the remote process's added fd number */
230c97aedc5SSargun Dhillon #define SECCOMP_IOCTL_NOTIF_ADDFD	SECCOMP_IOW(3,	\
231c97aedc5SSargun Dhillon 						struct seccomp_notif_addfd)
232c97aedc5SSargun Dhillon 
233c97aedc5SSargun Dhillon /* valid flags for seccomp_notif_addfd */
234c97aedc5SSargun Dhillon #define SECCOMP_ADDFD_FLAG_SETFD	(1UL << 0) /* Specify remote fd */
235c97aedc5SSargun Dhillon 
236c97aedc5SSargun Dhillon struct seccomp_notif_addfd {
237c97aedc5SSargun Dhillon 	__u64 id;
238c97aedc5SSargun Dhillon 	__u32 flags;
239c97aedc5SSargun Dhillon 	__u32 srcfd;
240c97aedc5SSargun Dhillon 	__u32 newfd;
241c97aedc5SSargun Dhillon 	__u32 newfd_flags;
242c97aedc5SSargun Dhillon };
243c97aedc5SSargun Dhillon #endif
244c97aedc5SSargun Dhillon 
245e540ad97SRodrigo Campos #ifndef SECCOMP_ADDFD_FLAG_SEND
246e540ad97SRodrigo Campos #define SECCOMP_ADDFD_FLAG_SEND	(1UL << 1) /* Addfd and return it, atomically */
247e540ad97SRodrigo Campos #endif
248e540ad97SRodrigo Campos 
249c97aedc5SSargun Dhillon struct seccomp_notif_addfd_small {
250c97aedc5SSargun Dhillon 	__u64 id;
251c97aedc5SSargun Dhillon 	char weird[4];
252c97aedc5SSargun Dhillon };
253c97aedc5SSargun Dhillon #define SECCOMP_IOCTL_NOTIF_ADDFD_SMALL	\
254c97aedc5SSargun Dhillon 	SECCOMP_IOW(3, struct seccomp_notif_addfd_small)
255c97aedc5SSargun Dhillon 
256c97aedc5SSargun Dhillon struct seccomp_notif_addfd_big {
257c97aedc5SSargun Dhillon 	union {
258c97aedc5SSargun Dhillon 		struct seccomp_notif_addfd addfd;
259c97aedc5SSargun Dhillon 		char buf[sizeof(struct seccomp_notif_addfd) + 8];
260c97aedc5SSargun Dhillon 	};
261c97aedc5SSargun Dhillon };
262c97aedc5SSargun Dhillon #define SECCOMP_IOCTL_NOTIF_ADDFD_BIG	\
263c97aedc5SSargun Dhillon 	SECCOMP_IOWR(3, struct seccomp_notif_addfd_big)
264c97aedc5SSargun Dhillon 
26588282297STycho Andersen #ifndef PTRACE_EVENTMSG_SYSCALL_ENTRY
26688282297STycho Andersen #define PTRACE_EVENTMSG_SYSCALL_ENTRY	1
26788282297STycho Andersen #define PTRACE_EVENTMSG_SYSCALL_EXIT	2
26888282297STycho Andersen #endif
26988282297STycho Andersen 
2702aa8d8d0SChristian Brauner #ifndef SECCOMP_USER_NOTIF_FLAG_CONTINUE
2712aa8d8d0SChristian Brauner #define SECCOMP_USER_NOTIF_FLAG_CONTINUE 0x00000001
2722aa8d8d0SChristian Brauner #endif
2732aa8d8d0SChristian Brauner 
27451891498STycho Andersen #ifndef SECCOMP_FILTER_FLAG_TSYNC_ESRCH
27551891498STycho Andersen #define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4)
27651891498STycho Andersen #endif
27751891498STycho Andersen 
2783b96a9c5SSargun Dhillon #ifndef SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV
2793b96a9c5SSargun Dhillon #define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5)
2803b96a9c5SSargun Dhillon #endif
2813b96a9c5SSargun Dhillon 
282f3e1821dSKees Cook #ifndef seccomp
seccomp(unsigned int op,unsigned int flags,void * args)283f3e1821dSKees Cook int seccomp(unsigned int op, unsigned int flags, void *args)
284f3e1821dSKees Cook {
285f3e1821dSKees Cook 	errno = 0;
286f3e1821dSKees Cook 	return syscall(__NR_seccomp, op, flags, args);
287f3e1821dSKees Cook }
288c99ee51aSKees Cook #endif
289c99ee51aSKees Cook 
2903e7ed9ceSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
291c99ee51aSKees Cook #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]))
2923e7ed9ceSIlya Leoshkevich #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
293c385d0dbSMichael Ellerman #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]) + sizeof(__u32))
294c385d0dbSMichael Ellerman #else
2953e7ed9ceSIlya Leoshkevich #error "wut? Unknown __BYTE_ORDER__?!"
296c385d0dbSMichael Ellerman #endif
297c99ee51aSKees Cook 
298c99ee51aSKees Cook #define SIBLING_EXIT_UNKILLED	0xbadbeef
299c99ee51aSKees Cook #define SIBLING_EXIT_FAILURE	0xbadface
300c99ee51aSKees Cook #define SIBLING_EXIT_NEWPRIVS	0xbadfeed
301c99ee51aSKees Cook 
__filecmp(pid_t pid1,pid_t pid2,int fd1,int fd2)302cf8918dbSKees Cook static int __filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
303cf8918dbSKees Cook {
304cf8918dbSKees Cook #ifdef __NR_kcmp
305cf8918dbSKees Cook 	errno = 0;
306cf8918dbSKees Cook 	return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
307cf8918dbSKees Cook #else
308cf8918dbSKees Cook 	errno = ENOSYS;
309cf8918dbSKees Cook 	return -1;
310cf8918dbSKees Cook #endif
311cf8918dbSKees Cook }
312cf8918dbSKees Cook 
313cf8918dbSKees Cook /* Have TH_LOG report actual location filecmp() is used. */
314cf8918dbSKees Cook #define filecmp(pid1, pid2, fd1, fd2)	({		\
315cf8918dbSKees Cook 	int _ret;					\
316cf8918dbSKees Cook 							\
317cf8918dbSKees Cook 	_ret = __filecmp(pid1, pid2, fd1, fd2);		\
318cf8918dbSKees Cook 	if (_ret != 0) {				\
319cf8918dbSKees Cook 		if (_ret < 0 && errno == ENOSYS) {	\
320cf8918dbSKees Cook 			TH_LOG("kcmp() syscall missing (test is less accurate)");\
321cf8918dbSKees Cook 			_ret = 0;			\
322cf8918dbSKees Cook 		}					\
323cf8918dbSKees Cook 	}						\
324cf8918dbSKees Cook 	_ret; })
325cf8918dbSKees Cook 
TEST(kcmp)326cf8918dbSKees Cook TEST(kcmp)
327cf8918dbSKees Cook {
328cf8918dbSKees Cook 	int ret;
329cf8918dbSKees Cook 
330cf8918dbSKees Cook 	ret = __filecmp(getpid(), getpid(), 1, 1);
331cf8918dbSKees Cook 	EXPECT_EQ(ret, 0);
332cf8918dbSKees Cook 	if (ret != 0 && errno == ENOSYS)
333bfe3911aSChris Wilson 		SKIP(return, "Kernel does not support kcmp() (missing CONFIG_KCMP?)");
334cf8918dbSKees Cook }
335cf8918dbSKees Cook 
TEST(mode_strict_support)336c99ee51aSKees Cook TEST(mode_strict_support)
337c99ee51aSKees Cook {
338c99ee51aSKees Cook 	long ret;
339c99ee51aSKees Cook 
340c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, NULL, NULL);
341c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
342c99ee51aSKees Cook 		TH_LOG("Kernel does not support CONFIG_SECCOMP");
343c99ee51aSKees Cook 	}
344369130b6SMickaël Salaün 	syscall(__NR_exit, 0);
345c99ee51aSKees Cook }
346c99ee51aSKees Cook 
TEST_SIGNAL(mode_strict_cannot_call_prctl,SIGKILL)347c99ee51aSKees Cook TEST_SIGNAL(mode_strict_cannot_call_prctl, SIGKILL)
348c99ee51aSKees Cook {
349c99ee51aSKees Cook 	long ret;
350c99ee51aSKees Cook 
351c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, NULL, NULL);
352c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
353c99ee51aSKees Cook 		TH_LOG("Kernel does not support CONFIG_SECCOMP");
354c99ee51aSKees Cook 	}
355c99ee51aSKees Cook 	syscall(__NR_prctl, PR_SET_SECCOMP, SECCOMP_MODE_FILTER,
356c99ee51aSKees Cook 		NULL, NULL, NULL);
357c99ee51aSKees Cook 	EXPECT_FALSE(true) {
358c99ee51aSKees Cook 		TH_LOG("Unreachable!");
359c99ee51aSKees Cook 	}
360c99ee51aSKees Cook }
361c99ee51aSKees Cook 
362c99ee51aSKees Cook /* Note! This doesn't test no new privs behavior */
TEST(no_new_privs_support)363c99ee51aSKees Cook TEST(no_new_privs_support)
364c99ee51aSKees Cook {
365c99ee51aSKees Cook 	long ret;
366c99ee51aSKees Cook 
367c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
368c99ee51aSKees Cook 	EXPECT_EQ(0, ret) {
369c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
370c99ee51aSKees Cook 	}
371c99ee51aSKees Cook }
372c99ee51aSKees Cook 
373f3f6e306SKees Cook /* Tests kernel support by checking for a copy_from_user() fault on NULL. */
TEST(mode_filter_support)374c99ee51aSKees Cook TEST(mode_filter_support)
375c99ee51aSKees Cook {
376c99ee51aSKees Cook 	long ret;
377c99ee51aSKees Cook 
378c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
379c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
380c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
381c99ee51aSKees Cook 	}
382c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, NULL, NULL);
383c99ee51aSKees Cook 	EXPECT_EQ(-1, ret);
384c99ee51aSKees Cook 	EXPECT_EQ(EFAULT, errno) {
385c99ee51aSKees Cook 		TH_LOG("Kernel does not support CONFIG_SECCOMP_FILTER!");
386c99ee51aSKees Cook 	}
387c99ee51aSKees Cook }
388c99ee51aSKees Cook 
TEST(mode_filter_without_nnp)389c99ee51aSKees Cook TEST(mode_filter_without_nnp)
390c99ee51aSKees Cook {
391c99ee51aSKees Cook 	struct sock_filter filter[] = {
392c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
393c99ee51aSKees Cook 	};
394c99ee51aSKees Cook 	struct sock_fprog prog = {
395c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
396c99ee51aSKees Cook 		.filter = filter,
397c99ee51aSKees Cook 	};
398c99ee51aSKees Cook 	long ret;
399fc1e3980SGautam Menghani 	cap_t cap = cap_get_proc();
400fc1e3980SGautam Menghani 	cap_flag_value_t is_cap_sys_admin = 0;
401c99ee51aSKees Cook 
402c99ee51aSKees Cook 	ret = prctl(PR_GET_NO_NEW_PRIVS, 0, NULL, 0, 0);
403c99ee51aSKees Cook 	ASSERT_LE(0, ret) {
404c99ee51aSKees Cook 		TH_LOG("Expected 0 or unsupported for NO_NEW_PRIVS");
405c99ee51aSKees Cook 	}
406c99ee51aSKees Cook 	errno = 0;
407c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
408c99ee51aSKees Cook 	/* Succeeds with CAP_SYS_ADMIN, fails without */
409fc1e3980SGautam Menghani 	cap_get_flag(cap, CAP_SYS_ADMIN, CAP_EFFECTIVE, &is_cap_sys_admin);
410fc1e3980SGautam Menghani 	if (!is_cap_sys_admin) {
411c99ee51aSKees Cook 		EXPECT_EQ(-1, ret);
412c99ee51aSKees Cook 		EXPECT_EQ(EACCES, errno);
413c99ee51aSKees Cook 	} else {
414c99ee51aSKees Cook 		EXPECT_EQ(0, ret);
415c99ee51aSKees Cook 	}
416c99ee51aSKees Cook }
417c99ee51aSKees Cook 
418c99ee51aSKees Cook #define MAX_INSNS_PER_PATH 32768
419c99ee51aSKees Cook 
TEST(filter_size_limits)420c99ee51aSKees Cook TEST(filter_size_limits)
421c99ee51aSKees Cook {
422c99ee51aSKees Cook 	int i;
423c99ee51aSKees Cook 	int count = BPF_MAXINSNS + 1;
424c99ee51aSKees Cook 	struct sock_filter allow[] = {
425c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
426c99ee51aSKees Cook 	};
427c99ee51aSKees Cook 	struct sock_filter *filter;
428c99ee51aSKees Cook 	struct sock_fprog prog = { };
429c99ee51aSKees Cook 	long ret;
430c99ee51aSKees Cook 
431c99ee51aSKees Cook 	filter = calloc(count, sizeof(*filter));
432c99ee51aSKees Cook 	ASSERT_NE(NULL, filter);
433c99ee51aSKees Cook 
434c99ee51aSKees Cook 	for (i = 0; i < count; i++)
435c99ee51aSKees Cook 		filter[i] = allow[0];
436c99ee51aSKees Cook 
437c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
438c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
439c99ee51aSKees Cook 
440c99ee51aSKees Cook 	prog.filter = filter;
441c99ee51aSKees Cook 	prog.len = count;
442c99ee51aSKees Cook 
443c99ee51aSKees Cook 	/* Too many filter instructions in a single filter. */
444c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
445c99ee51aSKees Cook 	ASSERT_NE(0, ret) {
446c99ee51aSKees Cook 		TH_LOG("Installing %d insn filter was allowed", prog.len);
447c99ee51aSKees Cook 	}
448c99ee51aSKees Cook 
449c99ee51aSKees Cook 	/* One less is okay, though. */
450c99ee51aSKees Cook 	prog.len -= 1;
451c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
452c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
453c99ee51aSKees Cook 		TH_LOG("Installing %d insn filter wasn't allowed", prog.len);
454c99ee51aSKees Cook 	}
455c99ee51aSKees Cook }
456c99ee51aSKees Cook 
TEST(filter_chain_limits)457c99ee51aSKees Cook TEST(filter_chain_limits)
458c99ee51aSKees Cook {
459c99ee51aSKees Cook 	int i;
460c99ee51aSKees Cook 	int count = BPF_MAXINSNS;
461c99ee51aSKees Cook 	struct sock_filter allow[] = {
462c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
463c99ee51aSKees Cook 	};
464c99ee51aSKees Cook 	struct sock_filter *filter;
465c99ee51aSKees Cook 	struct sock_fprog prog = { };
466c99ee51aSKees Cook 	long ret;
467c99ee51aSKees Cook 
468c99ee51aSKees Cook 	filter = calloc(count, sizeof(*filter));
469c99ee51aSKees Cook 	ASSERT_NE(NULL, filter);
470c99ee51aSKees Cook 
471c99ee51aSKees Cook 	for (i = 0; i < count; i++)
472c99ee51aSKees Cook 		filter[i] = allow[0];
473c99ee51aSKees Cook 
474c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
475c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
476c99ee51aSKees Cook 
477c99ee51aSKees Cook 	prog.filter = filter;
478c99ee51aSKees Cook 	prog.len = 1;
479c99ee51aSKees Cook 
480c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
481c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
482c99ee51aSKees Cook 
483c99ee51aSKees Cook 	prog.len = count;
484c99ee51aSKees Cook 
485c99ee51aSKees Cook 	/* Too many total filter instructions. */
486c99ee51aSKees Cook 	for (i = 0; i < MAX_INSNS_PER_PATH; i++) {
487c99ee51aSKees Cook 		ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
488c99ee51aSKees Cook 		if (ret != 0)
489c99ee51aSKees Cook 			break;
490c99ee51aSKees Cook 	}
491c99ee51aSKees Cook 	ASSERT_NE(0, ret) {
492c99ee51aSKees Cook 		TH_LOG("Allowed %d %d-insn filters (total with penalties:%d)",
493c99ee51aSKees Cook 		       i, count, i * (count + 4));
494c99ee51aSKees Cook 	}
495c99ee51aSKees Cook }
496c99ee51aSKees Cook 
TEST(mode_filter_cannot_move_to_strict)497c99ee51aSKees Cook TEST(mode_filter_cannot_move_to_strict)
498c99ee51aSKees Cook {
499c99ee51aSKees Cook 	struct sock_filter filter[] = {
500c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
501c99ee51aSKees Cook 	};
502c99ee51aSKees Cook 	struct sock_fprog prog = {
503c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
504c99ee51aSKees Cook 		.filter = filter,
505c99ee51aSKees Cook 	};
506c99ee51aSKees Cook 	long ret;
507c99ee51aSKees Cook 
508c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
509c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
510c99ee51aSKees Cook 
511c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
512c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
513c99ee51aSKees Cook 
514c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0);
515c99ee51aSKees Cook 	EXPECT_EQ(-1, ret);
516c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno);
517c99ee51aSKees Cook }
518c99ee51aSKees Cook 
519c99ee51aSKees Cook 
TEST(mode_filter_get_seccomp)520c99ee51aSKees Cook TEST(mode_filter_get_seccomp)
521c99ee51aSKees Cook {
522c99ee51aSKees Cook 	struct sock_filter filter[] = {
523c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
524c99ee51aSKees Cook 	};
525c99ee51aSKees Cook 	struct sock_fprog prog = {
526c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
527c99ee51aSKees Cook 		.filter = filter,
528c99ee51aSKees Cook 	};
529c99ee51aSKees Cook 	long ret;
530c99ee51aSKees Cook 
531c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
532c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
533c99ee51aSKees Cook 
534c99ee51aSKees Cook 	ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
535c99ee51aSKees Cook 	EXPECT_EQ(0, ret);
536c99ee51aSKees Cook 
537c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
538c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
539c99ee51aSKees Cook 
540c99ee51aSKees Cook 	ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
541c99ee51aSKees Cook 	EXPECT_EQ(2, ret);
542c99ee51aSKees Cook }
543c99ee51aSKees Cook 
544c99ee51aSKees Cook 
TEST(ALLOW_all)545c99ee51aSKees Cook TEST(ALLOW_all)
546c99ee51aSKees Cook {
547c99ee51aSKees Cook 	struct sock_filter filter[] = {
548c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
549c99ee51aSKees Cook 	};
550c99ee51aSKees Cook 	struct sock_fprog prog = {
551c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
552c99ee51aSKees Cook 		.filter = filter,
553c99ee51aSKees Cook 	};
554c99ee51aSKees Cook 	long ret;
555c99ee51aSKees Cook 
556c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
557c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
558c99ee51aSKees Cook 
559c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
560c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
561c99ee51aSKees Cook }
562c99ee51aSKees Cook 
TEST(empty_prog)563c99ee51aSKees Cook TEST(empty_prog)
564c99ee51aSKees Cook {
565c99ee51aSKees Cook 	struct sock_filter filter[] = {
566c99ee51aSKees Cook 	};
567c99ee51aSKees Cook 	struct sock_fprog prog = {
568c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
569c99ee51aSKees Cook 		.filter = filter,
570c99ee51aSKees Cook 	};
571c99ee51aSKees Cook 	long ret;
572c99ee51aSKees Cook 
573c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
574c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
575c99ee51aSKees Cook 
576c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
577c99ee51aSKees Cook 	EXPECT_EQ(-1, ret);
578c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno);
579c99ee51aSKees Cook }
580c99ee51aSKees Cook 
TEST(log_all)58159f5cf44STyler Hicks TEST(log_all)
58259f5cf44STyler Hicks {
58359f5cf44STyler Hicks 	struct sock_filter filter[] = {
58459f5cf44STyler Hicks 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG),
58559f5cf44STyler Hicks 	};
58659f5cf44STyler Hicks 	struct sock_fprog prog = {
58759f5cf44STyler Hicks 		.len = (unsigned short)ARRAY_SIZE(filter),
58859f5cf44STyler Hicks 		.filter = filter,
58959f5cf44STyler Hicks 	};
59059f5cf44STyler Hicks 	long ret;
59159f5cf44STyler Hicks 	pid_t parent = getppid();
59259f5cf44STyler Hicks 
59359f5cf44STyler Hicks 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
59459f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
59559f5cf44STyler Hicks 
59659f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
59759f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
59859f5cf44STyler Hicks 
59959f5cf44STyler Hicks 	/* getppid() should succeed and be logged (no check for logging) */
60059f5cf44STyler Hicks 	EXPECT_EQ(parent, syscall(__NR_getppid));
60159f5cf44STyler Hicks }
60259f5cf44STyler Hicks 
TEST_SIGNAL(unknown_ret_is_kill_inside,SIGSYS)603c99ee51aSKees Cook TEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS)
604c99ee51aSKees Cook {
605c99ee51aSKees Cook 	struct sock_filter filter[] = {
606c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, 0x10000000U),
607c99ee51aSKees Cook 	};
608c99ee51aSKees Cook 	struct sock_fprog prog = {
609c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
610c99ee51aSKees Cook 		.filter = filter,
611c99ee51aSKees Cook 	};
612c99ee51aSKees Cook 	long ret;
613c99ee51aSKees Cook 
614c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
615c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
616c99ee51aSKees Cook 
617c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
618c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
619c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid)) {
620c99ee51aSKees Cook 		TH_LOG("getpid() shouldn't ever return");
621c99ee51aSKees Cook 	}
622c99ee51aSKees Cook }
623c99ee51aSKees Cook 
624c99ee51aSKees Cook /* return code >= 0x80000000 is unused. */
TEST_SIGNAL(unknown_ret_is_kill_above_allow,SIGSYS)625c99ee51aSKees Cook TEST_SIGNAL(unknown_ret_is_kill_above_allow, SIGSYS)
626c99ee51aSKees Cook {
627c99ee51aSKees Cook 	struct sock_filter filter[] = {
628c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, 0x90000000U),
629c99ee51aSKees Cook 	};
630c99ee51aSKees Cook 	struct sock_fprog prog = {
631c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
632c99ee51aSKees Cook 		.filter = filter,
633c99ee51aSKees Cook 	};
634c99ee51aSKees Cook 	long ret;
635c99ee51aSKees Cook 
636c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
637c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
638c99ee51aSKees Cook 
639c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
640c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
641c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid)) {
642c99ee51aSKees Cook 		TH_LOG("getpid() shouldn't ever return");
643c99ee51aSKees Cook 	}
644c99ee51aSKees Cook }
645c99ee51aSKees Cook 
TEST_SIGNAL(KILL_all,SIGSYS)646c99ee51aSKees Cook TEST_SIGNAL(KILL_all, SIGSYS)
647c99ee51aSKees Cook {
648c99ee51aSKees Cook 	struct sock_filter filter[] = {
649c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
650c99ee51aSKees Cook 	};
651c99ee51aSKees Cook 	struct sock_fprog prog = {
652c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
653c99ee51aSKees Cook 		.filter = filter,
654c99ee51aSKees Cook 	};
655c99ee51aSKees Cook 	long ret;
656c99ee51aSKees Cook 
657c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
658c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
659c99ee51aSKees Cook 
660c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
661c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
662c99ee51aSKees Cook }
663c99ee51aSKees Cook 
TEST_SIGNAL(KILL_one,SIGSYS)664c99ee51aSKees Cook TEST_SIGNAL(KILL_one, SIGSYS)
665c99ee51aSKees Cook {
666c99ee51aSKees Cook 	struct sock_filter filter[] = {
667c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
668c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
669c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
670c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
671c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
672c99ee51aSKees Cook 	};
673c99ee51aSKees Cook 	struct sock_fprog prog = {
674c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
675c99ee51aSKees Cook 		.filter = filter,
676c99ee51aSKees Cook 	};
677c99ee51aSKees Cook 	long ret;
678c99ee51aSKees Cook 	pid_t parent = getppid();
679c99ee51aSKees Cook 
680c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
681c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
682c99ee51aSKees Cook 
683c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
684c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
685c99ee51aSKees Cook 
686c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
687c99ee51aSKees Cook 	/* getpid() should never return. */
688c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid));
689c99ee51aSKees Cook }
690c99ee51aSKees Cook 
TEST_SIGNAL(KILL_one_arg_one,SIGSYS)691c99ee51aSKees Cook TEST_SIGNAL(KILL_one_arg_one, SIGSYS)
692c99ee51aSKees Cook {
693fd88d16cSRobert Sesek 	void *fatal_address;
694c99ee51aSKees Cook 	struct sock_filter filter[] = {
695c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
696c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
697fd88d16cSRobert Sesek 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_times, 1, 0),
698c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
699c99ee51aSKees Cook 		/* Only both with lower 32-bit for now. */
700c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)),
701fd88d16cSRobert Sesek 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K,
702fd88d16cSRobert Sesek 			(unsigned long)&fatal_address, 0, 1),
703c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
704c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
705c99ee51aSKees Cook 	};
706c99ee51aSKees Cook 	struct sock_fprog prog = {
707c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
708c99ee51aSKees Cook 		.filter = filter,
709c99ee51aSKees Cook 	};
710c99ee51aSKees Cook 	long ret;
711c99ee51aSKees Cook 	pid_t parent = getppid();
712fd88d16cSRobert Sesek 	struct tms timebuf;
713fd88d16cSRobert Sesek 	clock_t clock = times(&timebuf);
714c99ee51aSKees Cook 
715c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
716c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
717c99ee51aSKees Cook 
718c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
719c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
720c99ee51aSKees Cook 
721c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
722fd88d16cSRobert Sesek 	EXPECT_LE(clock, syscall(__NR_times, &timebuf));
723fd88d16cSRobert Sesek 	/* times() should never return. */
724fd88d16cSRobert Sesek 	EXPECT_EQ(0, syscall(__NR_times, &fatal_address));
725c99ee51aSKees Cook }
726c99ee51aSKees Cook 
TEST_SIGNAL(KILL_one_arg_six,SIGSYS)727c99ee51aSKees Cook TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
728c99ee51aSKees Cook {
729fd88d16cSRobert Sesek #ifndef __NR_mmap2
730fd88d16cSRobert Sesek 	int sysno = __NR_mmap;
731fd88d16cSRobert Sesek #else
732fd88d16cSRobert Sesek 	int sysno = __NR_mmap2;
733fd88d16cSRobert Sesek #endif
734c99ee51aSKees Cook 	struct sock_filter filter[] = {
735c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
736c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
737fd88d16cSRobert Sesek 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sysno, 1, 0),
738c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
739c99ee51aSKees Cook 		/* Only both with lower 32-bit for now. */
740c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)),
741c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1),
742c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
743c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
744c99ee51aSKees Cook 	};
745c99ee51aSKees Cook 	struct sock_fprog prog = {
746c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
747c99ee51aSKees Cook 		.filter = filter,
748c99ee51aSKees Cook 	};
749c99ee51aSKees Cook 	long ret;
750c99ee51aSKees Cook 	pid_t parent = getppid();
751fd88d16cSRobert Sesek 	int fd;
752fd88d16cSRobert Sesek 	void *map1, *map2;
7532ce47b44SBamvor Jian Zhang 	int page_size = sysconf(_SC_PAGESIZE);
7542ce47b44SBamvor Jian Zhang 
7552ce47b44SBamvor Jian Zhang 	ASSERT_LT(0, page_size);
756c99ee51aSKees Cook 
757c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
758c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
759c99ee51aSKees Cook 
760c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
761c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
762c99ee51aSKees Cook 
763fd88d16cSRobert Sesek 	fd = open("/dev/zero", O_RDONLY);
764fd88d16cSRobert Sesek 	ASSERT_NE(-1, fd);
765fd88d16cSRobert Sesek 
766c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
767fd88d16cSRobert Sesek 	map1 = (void *)syscall(sysno,
7682ce47b44SBamvor Jian Zhang 		NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size);
769fd88d16cSRobert Sesek 	EXPECT_NE(MAP_FAILED, map1);
770fd88d16cSRobert Sesek 	/* mmap2() should never return. */
771fd88d16cSRobert Sesek 	map2 = (void *)syscall(sysno,
7722ce47b44SBamvor Jian Zhang 		 NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
773fd88d16cSRobert Sesek 	EXPECT_EQ(MAP_FAILED, map2);
774fd88d16cSRobert Sesek 
775fd88d16cSRobert Sesek 	/* The test failed, so clean up the resources. */
7762ce47b44SBamvor Jian Zhang 	munmap(map1, page_size);
7772ce47b44SBamvor Jian Zhang 	munmap(map2, page_size);
778fd88d16cSRobert Sesek 	close(fd);
779c99ee51aSKees Cook }
780c99ee51aSKees Cook 
781f3e1821dSKees Cook /* This is a thread task to die via seccomp filter violation. */
kill_thread(void * data)782f3e1821dSKees Cook void *kill_thread(void *data)
783f3e1821dSKees Cook {
784f3e1821dSKees Cook 	bool die = (bool)data;
785f3e1821dSKees Cook 
786f3e1821dSKees Cook 	if (die) {
787f4b1e2ccSTerry Tritton 		syscall(__NR_getpid);
788f3e1821dSKees Cook 		return (void *)SIBLING_EXIT_FAILURE;
789f3e1821dSKees Cook 	}
790f3e1821dSKees Cook 
791f3e1821dSKees Cook 	return (void *)SIBLING_EXIT_UNKILLED;
792f3e1821dSKees Cook }
793f3e1821dSKees Cook 
7943932fcecSKees Cook enum kill_t {
7953932fcecSKees Cook 	KILL_THREAD,
7963932fcecSKees Cook 	KILL_PROCESS,
7973932fcecSKees Cook 	RET_UNKNOWN
7983932fcecSKees Cook };
7993932fcecSKees Cook 
800f3e1821dSKees Cook /* Prepare a thread that will kill itself or both of us. */
kill_thread_or_group(struct __test_metadata * _metadata,enum kill_t kill_how)8013932fcecSKees Cook void kill_thread_or_group(struct __test_metadata *_metadata,
8023932fcecSKees Cook 			  enum kill_t kill_how)
803f3e1821dSKees Cook {
804f3e1821dSKees Cook 	pthread_t thread;
805f3e1821dSKees Cook 	void *status;
806f4b1e2ccSTerry Tritton 	/* Kill only when calling __NR_getpid. */
807f3e1821dSKees Cook 	struct sock_filter filter_thread[] = {
808f3e1821dSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
809f3e1821dSKees Cook 			offsetof(struct seccomp_data, nr)),
810f4b1e2ccSTerry Tritton 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
811f3e1821dSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD),
812f3e1821dSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
813f3e1821dSKees Cook 	};
814f3e1821dSKees Cook 	struct sock_fprog prog_thread = {
815f3e1821dSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter_thread),
816f3e1821dSKees Cook 		.filter = filter_thread,
817f3e1821dSKees Cook 	};
8183ce4b78fSYiFei Zhu 	int kill = kill_how == KILL_PROCESS ? SECCOMP_RET_KILL_PROCESS : 0xAAAAAAAA;
819f3e1821dSKees Cook 	struct sock_filter filter_process[] = {
820f3e1821dSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
821f3e1821dSKees Cook 			offsetof(struct seccomp_data, nr)),
822f4b1e2ccSTerry Tritton 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
8233932fcecSKees Cook 		BPF_STMT(BPF_RET|BPF_K, kill),
824f3e1821dSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
825f3e1821dSKees Cook 	};
826f3e1821dSKees Cook 	struct sock_fprog prog_process = {
827f3e1821dSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter_process),
828f3e1821dSKees Cook 		.filter = filter_process,
829f3e1821dSKees Cook 	};
830f3e1821dSKees Cook 
831f3e1821dSKees Cook 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
832f3e1821dSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
833f3e1821dSKees Cook 	}
834f3e1821dSKees Cook 
835f3e1821dSKees Cook 	ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0,
8363932fcecSKees Cook 			     kill_how == KILL_THREAD ? &prog_thread
8373932fcecSKees Cook 						     : &prog_process));
838f3e1821dSKees Cook 
839f3e1821dSKees Cook 	/*
840f3e1821dSKees Cook 	 * Add the KILL_THREAD rule again to make sure that the KILL_PROCESS
841f3e1821dSKees Cook 	 * flag cannot be downgraded by a new filter.
842f3e1821dSKees Cook 	 */
8433932fcecSKees Cook 	if (kill_how == KILL_PROCESS)
844f3e1821dSKees Cook 		ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog_thread));
845f3e1821dSKees Cook 
846f3e1821dSKees Cook 	/* Start a thread that will exit immediately. */
847f3e1821dSKees Cook 	ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)false));
848f3e1821dSKees Cook 	ASSERT_EQ(0, pthread_join(thread, &status));
849f3e1821dSKees Cook 	ASSERT_EQ(SIBLING_EXIT_UNKILLED, (unsigned long)status);
850f3e1821dSKees Cook 
851f3e1821dSKees Cook 	/* Start a thread that will die immediately. */
852f3e1821dSKees Cook 	ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)true));
853f3e1821dSKees Cook 	ASSERT_EQ(0, pthread_join(thread, &status));
854f3e1821dSKees Cook 	ASSERT_NE(SIBLING_EXIT_FAILURE, (unsigned long)status);
855f3e1821dSKees Cook 
856f3e1821dSKees Cook 	/*
857f3e1821dSKees Cook 	 * If we get here, only the spawned thread died. Let the parent know
858f3e1821dSKees Cook 	 * the whole process didn't die (i.e. this thread, the spawner,
859f3e1821dSKees Cook 	 * stayed running).
860f3e1821dSKees Cook 	 */
861f3e1821dSKees Cook 	exit(42);
862f3e1821dSKees Cook }
863f3e1821dSKees Cook 
TEST(KILL_thread)864f3e1821dSKees Cook TEST(KILL_thread)
865f3e1821dSKees Cook {
866f3e1821dSKees Cook 	int status;
867f3e1821dSKees Cook 	pid_t child_pid;
868f3e1821dSKees Cook 
869f3e1821dSKees Cook 	child_pid = fork();
870f3e1821dSKees Cook 	ASSERT_LE(0, child_pid);
871f3e1821dSKees Cook 	if (child_pid == 0) {
8723932fcecSKees Cook 		kill_thread_or_group(_metadata, KILL_THREAD);
873f3e1821dSKees Cook 		_exit(38);
874f3e1821dSKees Cook 	}
875f3e1821dSKees Cook 
876f3e1821dSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
877f3e1821dSKees Cook 
878f3e1821dSKees Cook 	/* If only the thread was killed, we'll see exit 42. */
879f3e1821dSKees Cook 	ASSERT_TRUE(WIFEXITED(status));
880f3e1821dSKees Cook 	ASSERT_EQ(42, WEXITSTATUS(status));
881f3e1821dSKees Cook }
882f3e1821dSKees Cook 
TEST(KILL_process)883f3e1821dSKees Cook TEST(KILL_process)
884f3e1821dSKees Cook {
885f3e1821dSKees Cook 	int status;
886f3e1821dSKees Cook 	pid_t child_pid;
887f3e1821dSKees Cook 
888f3e1821dSKees Cook 	child_pid = fork();
889f3e1821dSKees Cook 	ASSERT_LE(0, child_pid);
890f3e1821dSKees Cook 	if (child_pid == 0) {
8913932fcecSKees Cook 		kill_thread_or_group(_metadata, KILL_PROCESS);
892f3e1821dSKees Cook 		_exit(38);
893f3e1821dSKees Cook 	}
894f3e1821dSKees Cook 
895f3e1821dSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
896f3e1821dSKees Cook 
897f3e1821dSKees Cook 	/* If the entire process was killed, we'll see SIGSYS. */
898f3e1821dSKees Cook 	ASSERT_TRUE(WIFSIGNALED(status));
899f3e1821dSKees Cook 	ASSERT_EQ(SIGSYS, WTERMSIG(status));
900f3e1821dSKees Cook }
901f3e1821dSKees Cook 
TEST(KILL_unknown)9023932fcecSKees Cook TEST(KILL_unknown)
9033932fcecSKees Cook {
9043932fcecSKees Cook 	int status;
9053932fcecSKees Cook 	pid_t child_pid;
9063932fcecSKees Cook 
9073932fcecSKees Cook 	child_pid = fork();
9083932fcecSKees Cook 	ASSERT_LE(0, child_pid);
9093932fcecSKees Cook 	if (child_pid == 0) {
9103932fcecSKees Cook 		kill_thread_or_group(_metadata, RET_UNKNOWN);
9113932fcecSKees Cook 		_exit(38);
9123932fcecSKees Cook 	}
9133932fcecSKees Cook 
9143932fcecSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
9153932fcecSKees Cook 
9163932fcecSKees Cook 	/* If the entire process was killed, we'll see SIGSYS. */
9173932fcecSKees Cook 	EXPECT_TRUE(WIFSIGNALED(status)) {
9183932fcecSKees Cook 		TH_LOG("Unknown SECCOMP_RET is only killing the thread?");
9193932fcecSKees Cook 	}
9203932fcecSKees Cook 	ASSERT_EQ(SIGSYS, WTERMSIG(status));
9213932fcecSKees Cook }
9223932fcecSKees Cook 
923c99ee51aSKees Cook /* TODO(wad) add 64-bit versus 32-bit arg tests. */
TEST(arg_out_of_range)924c99ee51aSKees Cook TEST(arg_out_of_range)
925c99ee51aSKees Cook {
926c99ee51aSKees Cook 	struct sock_filter filter[] = {
927c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(6)),
928c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
929c99ee51aSKees Cook 	};
930c99ee51aSKees Cook 	struct sock_fprog prog = {
931c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
932c99ee51aSKees Cook 		.filter = filter,
933c99ee51aSKees Cook 	};
934c99ee51aSKees Cook 	long ret;
935c99ee51aSKees Cook 
936c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
937c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
938c99ee51aSKees Cook 
939c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
940c99ee51aSKees Cook 	EXPECT_EQ(-1, ret);
941c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno);
942c99ee51aSKees Cook }
943c99ee51aSKees Cook 
944f3f6e306SKees Cook #define ERRNO_FILTER(name, errno)					\
945f3f6e306SKees Cook 	struct sock_filter _read_filter_##name[] = {			\
946f3f6e306SKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,				\
947f3f6e306SKees Cook 			offsetof(struct seccomp_data, nr)),		\
948f3f6e306SKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),	\
949f3f6e306SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | errno),	\
950f3f6e306SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),		\
951f3f6e306SKees Cook 	};								\
952f3f6e306SKees Cook 	struct sock_fprog prog_##name = {				\
953f3f6e306SKees Cook 		.len = (unsigned short)ARRAY_SIZE(_read_filter_##name),	\
954f3f6e306SKees Cook 		.filter = _read_filter_##name,				\
955f3f6e306SKees Cook 	}
956f3f6e306SKees Cook 
957f3f6e306SKees Cook /* Make sure basic errno values are correctly passed through a filter. */
TEST(ERRNO_valid)958c99ee51aSKees Cook TEST(ERRNO_valid)
959c99ee51aSKees Cook {
960f3f6e306SKees Cook 	ERRNO_FILTER(valid, E2BIG);
961c99ee51aSKees Cook 	long ret;
962c99ee51aSKees Cook 	pid_t parent = getppid();
963c99ee51aSKees Cook 
964c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
965c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
966c99ee51aSKees Cook 
967f3f6e306SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_valid);
968c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
969c99ee51aSKees Cook 
970c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
9712bfed7d2SJann Horn 	EXPECT_EQ(-1, read(-1, NULL, 0));
972c99ee51aSKees Cook 	EXPECT_EQ(E2BIG, errno);
973c99ee51aSKees Cook }
974c99ee51aSKees Cook 
975f3f6e306SKees Cook /* Make sure an errno of zero is correctly handled by the arch code. */
TEST(ERRNO_zero)976c99ee51aSKees Cook TEST(ERRNO_zero)
977c99ee51aSKees Cook {
978f3f6e306SKees Cook 	ERRNO_FILTER(zero, 0);
979c99ee51aSKees Cook 	long ret;
980c99ee51aSKees Cook 	pid_t parent = getppid();
981c99ee51aSKees Cook 
982c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
983c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
984c99ee51aSKees Cook 
985f3f6e306SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_zero);
986c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
987c99ee51aSKees Cook 
988c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
989c99ee51aSKees Cook 	/* "errno" of 0 is ok. */
9902bfed7d2SJann Horn 	EXPECT_EQ(0, read(-1, NULL, 0));
991c99ee51aSKees Cook }
992c99ee51aSKees Cook 
993f3f6e306SKees Cook /*
994f3f6e306SKees Cook  * The SECCOMP_RET_DATA mask is 16 bits wide, but errno is smaller.
995f3f6e306SKees Cook  * This tests that the errno value gets capped correctly, fixed by
996f3f6e306SKees Cook  * 580c57f10768 ("seccomp: cap SECCOMP_RET_ERRNO data to MAX_ERRNO").
997f3f6e306SKees Cook  */
TEST(ERRNO_capped)998c99ee51aSKees Cook TEST(ERRNO_capped)
999c99ee51aSKees Cook {
1000f3f6e306SKees Cook 	ERRNO_FILTER(capped, 4096);
1001c99ee51aSKees Cook 	long ret;
1002c99ee51aSKees Cook 	pid_t parent = getppid();
1003c99ee51aSKees Cook 
1004c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1005c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1006c99ee51aSKees Cook 
1007f3f6e306SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_capped);
1008c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1009c99ee51aSKees Cook 
1010c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
10112bfed7d2SJann Horn 	EXPECT_EQ(-1, read(-1, NULL, 0));
1012c99ee51aSKees Cook 	EXPECT_EQ(4095, errno);
1013c99ee51aSKees Cook }
1014c99ee51aSKees Cook 
1015f3f6e306SKees Cook /*
1016f3f6e306SKees Cook  * Filters are processed in reverse order: last applied is executed first.
1017f3f6e306SKees Cook  * Since only the SECCOMP_RET_ACTION mask is tested for return values, the
1018f3f6e306SKees Cook  * SECCOMP_RET_DATA mask results will follow the most recently applied
1019f3f6e306SKees Cook  * matching filter return (and not the lowest or highest value).
1020f3f6e306SKees Cook  */
TEST(ERRNO_order)1021f3f6e306SKees Cook TEST(ERRNO_order)
1022f3f6e306SKees Cook {
1023f3f6e306SKees Cook 	ERRNO_FILTER(first,  11);
1024f3f6e306SKees Cook 	ERRNO_FILTER(second, 13);
1025f3f6e306SKees Cook 	ERRNO_FILTER(third,  12);
1026f3f6e306SKees Cook 	long ret;
1027f3f6e306SKees Cook 	pid_t parent = getppid();
1028f3f6e306SKees Cook 
1029f3f6e306SKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1030f3f6e306SKees Cook 	ASSERT_EQ(0, ret);
1031f3f6e306SKees Cook 
1032f3f6e306SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_first);
1033f3f6e306SKees Cook 	ASSERT_EQ(0, ret);
1034f3f6e306SKees Cook 
1035f3f6e306SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_second);
1036f3f6e306SKees Cook 	ASSERT_EQ(0, ret);
1037f3f6e306SKees Cook 
1038f3f6e306SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_third);
1039f3f6e306SKees Cook 	ASSERT_EQ(0, ret);
1040f3f6e306SKees Cook 
1041f3f6e306SKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
10422bfed7d2SJann Horn 	EXPECT_EQ(-1, read(-1, NULL, 0));
1043f3f6e306SKees Cook 	EXPECT_EQ(12, errno);
1044f3f6e306SKees Cook }
1045f3f6e306SKees Cook 
FIXTURE(TRAP)10461ae81d78SKees Cook FIXTURE(TRAP) {
1047c99ee51aSKees Cook 	struct sock_fprog prog;
1048c99ee51aSKees Cook };
1049c99ee51aSKees Cook 
FIXTURE_SETUP(TRAP)1050c99ee51aSKees Cook FIXTURE_SETUP(TRAP)
1051c99ee51aSKees Cook {
1052c99ee51aSKees Cook 	struct sock_filter filter[] = {
1053c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
1054c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
1055c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
1056c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),
1057c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1058c99ee51aSKees Cook 	};
1059c99ee51aSKees Cook 
1060c99ee51aSKees Cook 	memset(&self->prog, 0, sizeof(self->prog));
1061c99ee51aSKees Cook 	self->prog.filter = malloc(sizeof(filter));
1062c99ee51aSKees Cook 	ASSERT_NE(NULL, self->prog.filter);
1063c99ee51aSKees Cook 	memcpy(self->prog.filter, filter, sizeof(filter));
1064c99ee51aSKees Cook 	self->prog.len = (unsigned short)ARRAY_SIZE(filter);
1065c99ee51aSKees Cook }
1066c99ee51aSKees Cook 
FIXTURE_TEARDOWN(TRAP)1067c99ee51aSKees Cook FIXTURE_TEARDOWN(TRAP)
1068c99ee51aSKees Cook {
1069c99ee51aSKees Cook 	if (self->prog.filter)
1070c99ee51aSKees Cook 		free(self->prog.filter);
1071c99ee51aSKees Cook }
1072c99ee51aSKees Cook 
TEST_F_SIGNAL(TRAP,dfl,SIGSYS)1073c99ee51aSKees Cook TEST_F_SIGNAL(TRAP, dfl, SIGSYS)
1074c99ee51aSKees Cook {
1075c99ee51aSKees Cook 	long ret;
1076c99ee51aSKees Cook 
1077c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1078c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1079c99ee51aSKees Cook 
1080c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
1081c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1082c99ee51aSKees Cook 	syscall(__NR_getpid);
1083c99ee51aSKees Cook }
1084c99ee51aSKees Cook 
1085c99ee51aSKees Cook /* Ensure that SIGSYS overrides SIG_IGN */
TEST_F_SIGNAL(TRAP,ign,SIGSYS)1086c99ee51aSKees Cook TEST_F_SIGNAL(TRAP, ign, SIGSYS)
1087c99ee51aSKees Cook {
1088c99ee51aSKees Cook 	long ret;
1089c99ee51aSKees Cook 
1090c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1091c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1092c99ee51aSKees Cook 
1093c99ee51aSKees Cook 	signal(SIGSYS, SIG_IGN);
1094c99ee51aSKees Cook 
1095c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
1096c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1097c99ee51aSKees Cook 	syscall(__NR_getpid);
1098c99ee51aSKees Cook }
1099c99ee51aSKees Cook 
110010859f38SKees Cook static siginfo_t TRAP_info;
1101c99ee51aSKees Cook static volatile int TRAP_nr;
TRAP_action(int nr,siginfo_t * info,void * void_context)1102c99ee51aSKees Cook static void TRAP_action(int nr, siginfo_t *info, void *void_context)
1103c99ee51aSKees Cook {
1104c99ee51aSKees Cook 	memcpy(&TRAP_info, info, sizeof(TRAP_info));
1105c99ee51aSKees Cook 	TRAP_nr = nr;
1106c99ee51aSKees Cook }
1107c99ee51aSKees Cook 
TEST_F(TRAP,handler)1108c99ee51aSKees Cook TEST_F(TRAP, handler)
1109c99ee51aSKees Cook {
1110c99ee51aSKees Cook 	int ret, test;
1111c99ee51aSKees Cook 	struct sigaction act;
1112c99ee51aSKees Cook 	sigset_t mask;
1113c99ee51aSKees Cook 
1114c99ee51aSKees Cook 	memset(&act, 0, sizeof(act));
1115c99ee51aSKees Cook 	sigemptyset(&mask);
1116c99ee51aSKees Cook 	sigaddset(&mask, SIGSYS);
1117c99ee51aSKees Cook 
1118c99ee51aSKees Cook 	act.sa_sigaction = &TRAP_action;
1119c99ee51aSKees Cook 	act.sa_flags = SA_SIGINFO;
1120c99ee51aSKees Cook 	ret = sigaction(SIGSYS, &act, NULL);
1121c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
1122c99ee51aSKees Cook 		TH_LOG("sigaction failed");
1123c99ee51aSKees Cook 	}
1124c99ee51aSKees Cook 	ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
1125c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
1126c99ee51aSKees Cook 		TH_LOG("sigprocmask failed");
1127c99ee51aSKees Cook 	}
1128c99ee51aSKees Cook 
1129c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1130c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1131c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
1132c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1133c99ee51aSKees Cook 	TRAP_nr = 0;
1134c99ee51aSKees Cook 	memset(&TRAP_info, 0, sizeof(TRAP_info));
1135c99ee51aSKees Cook 	/* Expect the registers to be rolled back. (nr = error) may vary
1136c99ee51aSKees Cook 	 * based on arch. */
1137c99ee51aSKees Cook 	ret = syscall(__NR_getpid);
1138c99ee51aSKees Cook 	/* Silence gcc warning about volatile. */
1139c99ee51aSKees Cook 	test = TRAP_nr;
1140c99ee51aSKees Cook 	EXPECT_EQ(SIGSYS, test);
1141c99ee51aSKees Cook 	struct local_sigsys {
1142c99ee51aSKees Cook 		void *_call_addr;	/* calling user insn */
1143c99ee51aSKees Cook 		int _syscall;		/* triggering system call number */
1144c99ee51aSKees Cook 		unsigned int _arch;	/* AUDIT_ARCH_* of syscall */
1145c99ee51aSKees Cook 	} *sigsys = (struct local_sigsys *)
1146c99ee51aSKees Cook #ifdef si_syscall
1147c99ee51aSKees Cook 		&(TRAP_info.si_call_addr);
1148c99ee51aSKees Cook #else
1149c99ee51aSKees Cook 		&TRAP_info.si_pid;
1150c99ee51aSKees Cook #endif
1151c99ee51aSKees Cook 	EXPECT_EQ(__NR_getpid, sigsys->_syscall);
1152c99ee51aSKees Cook 	/* Make sure arch is non-zero. */
1153c99ee51aSKees Cook 	EXPECT_NE(0, sigsys->_arch);
1154c99ee51aSKees Cook 	EXPECT_NE(0, (unsigned long)sigsys->_call_addr);
1155c99ee51aSKees Cook }
1156c99ee51aSKees Cook 
FIXTURE(precedence)11571ae81d78SKees Cook FIXTURE(precedence) {
1158c99ee51aSKees Cook 	struct sock_fprog allow;
115959f5cf44STyler Hicks 	struct sock_fprog log;
1160c99ee51aSKees Cook 	struct sock_fprog trace;
1161c99ee51aSKees Cook 	struct sock_fprog error;
1162c99ee51aSKees Cook 	struct sock_fprog trap;
1163c99ee51aSKees Cook 	struct sock_fprog kill;
1164c99ee51aSKees Cook };
1165c99ee51aSKees Cook 
FIXTURE_SETUP(precedence)1166c99ee51aSKees Cook FIXTURE_SETUP(precedence)
1167c99ee51aSKees Cook {
1168c99ee51aSKees Cook 	struct sock_filter allow_insns[] = {
1169c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1170c99ee51aSKees Cook 	};
117159f5cf44STyler Hicks 	struct sock_filter log_insns[] = {
117259f5cf44STyler Hicks 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
117359f5cf44STyler Hicks 			offsetof(struct seccomp_data, nr)),
117459f5cf44STyler Hicks 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
117559f5cf44STyler Hicks 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
117659f5cf44STyler Hicks 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG),
117759f5cf44STyler Hicks 	};
1178c99ee51aSKees Cook 	struct sock_filter trace_insns[] = {
1179c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
1180c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
1181c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
1182c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1183c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE),
1184c99ee51aSKees Cook 	};
1185c99ee51aSKees Cook 	struct sock_filter error_insns[] = {
1186c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
1187c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
1188c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
1189c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1190c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO),
1191c99ee51aSKees Cook 	};
1192c99ee51aSKees Cook 	struct sock_filter trap_insns[] = {
1193c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
1194c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
1195c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
1196c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1197c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),
1198c99ee51aSKees Cook 	};
1199c99ee51aSKees Cook 	struct sock_filter kill_insns[] = {
1200c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
1201c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
1202c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
1203c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1204c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
1205c99ee51aSKees Cook 	};
1206c99ee51aSKees Cook 
1207c99ee51aSKees Cook 	memset(self, 0, sizeof(*self));
1208c99ee51aSKees Cook #define FILTER_ALLOC(_x) \
1209c99ee51aSKees Cook 	self->_x.filter = malloc(sizeof(_x##_insns)); \
1210c99ee51aSKees Cook 	ASSERT_NE(NULL, self->_x.filter); \
1211c99ee51aSKees Cook 	memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \
1212c99ee51aSKees Cook 	self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns)
1213c99ee51aSKees Cook 	FILTER_ALLOC(allow);
121459f5cf44STyler Hicks 	FILTER_ALLOC(log);
1215c99ee51aSKees Cook 	FILTER_ALLOC(trace);
1216c99ee51aSKees Cook 	FILTER_ALLOC(error);
1217c99ee51aSKees Cook 	FILTER_ALLOC(trap);
1218c99ee51aSKees Cook 	FILTER_ALLOC(kill);
1219c99ee51aSKees Cook }
1220c99ee51aSKees Cook 
FIXTURE_TEARDOWN(precedence)1221c99ee51aSKees Cook FIXTURE_TEARDOWN(precedence)
1222c99ee51aSKees Cook {
1223c99ee51aSKees Cook #define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter)
1224c99ee51aSKees Cook 	FILTER_FREE(allow);
122559f5cf44STyler Hicks 	FILTER_FREE(log);
1226c99ee51aSKees Cook 	FILTER_FREE(trace);
1227c99ee51aSKees Cook 	FILTER_FREE(error);
1228c99ee51aSKees Cook 	FILTER_FREE(trap);
1229c99ee51aSKees Cook 	FILTER_FREE(kill);
1230c99ee51aSKees Cook }
1231c99ee51aSKees Cook 
TEST_F(precedence,allow_ok)1232c99ee51aSKees Cook TEST_F(precedence, allow_ok)
1233c99ee51aSKees Cook {
1234c99ee51aSKees Cook 	pid_t parent, res = 0;
1235c99ee51aSKees Cook 	long ret;
1236c99ee51aSKees Cook 
1237c99ee51aSKees Cook 	parent = getppid();
1238c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1239c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1240c99ee51aSKees Cook 
1241c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1242c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
124359f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
124459f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1245c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1246c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1247c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1248c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1249c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
1250c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1251c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill);
1252c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1253c99ee51aSKees Cook 	/* Should work just fine. */
1254c99ee51aSKees Cook 	res = syscall(__NR_getppid);
1255c99ee51aSKees Cook 	EXPECT_EQ(parent, res);
1256c99ee51aSKees Cook }
1257c99ee51aSKees Cook 
TEST_F_SIGNAL(precedence,kill_is_highest,SIGSYS)1258c99ee51aSKees Cook TEST_F_SIGNAL(precedence, kill_is_highest, SIGSYS)
1259c99ee51aSKees Cook {
1260c99ee51aSKees Cook 	pid_t parent, res = 0;
1261c99ee51aSKees Cook 	long ret;
1262c99ee51aSKees Cook 
1263c99ee51aSKees Cook 	parent = getppid();
1264c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1265c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1266c99ee51aSKees Cook 
1267c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1268c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
126959f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
127059f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1271c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1272c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1273c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1274c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1275c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
1276c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1277c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill);
1278c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1279c99ee51aSKees Cook 	/* Should work just fine. */
1280c99ee51aSKees Cook 	res = syscall(__NR_getppid);
1281c99ee51aSKees Cook 	EXPECT_EQ(parent, res);
1282c99ee51aSKees Cook 	/* getpid() should never return. */
1283c99ee51aSKees Cook 	res = syscall(__NR_getpid);
1284c99ee51aSKees Cook 	EXPECT_EQ(0, res);
1285c99ee51aSKees Cook }
1286c99ee51aSKees Cook 
TEST_F_SIGNAL(precedence,kill_is_highest_in_any_order,SIGSYS)1287c99ee51aSKees Cook TEST_F_SIGNAL(precedence, kill_is_highest_in_any_order, SIGSYS)
1288c99ee51aSKees Cook {
1289c99ee51aSKees Cook 	pid_t parent;
1290c99ee51aSKees Cook 	long ret;
1291c99ee51aSKees Cook 
1292c99ee51aSKees Cook 	parent = getppid();
1293c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1294c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1295c99ee51aSKees Cook 
1296c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1297c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1298c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill);
1299c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1300c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1301c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
130259f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
130359f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1304c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1305c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1306c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
1307c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1308c99ee51aSKees Cook 	/* Should work just fine. */
1309c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1310c99ee51aSKees Cook 	/* getpid() should never return. */
1311c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid));
1312c99ee51aSKees Cook }
1313c99ee51aSKees Cook 
TEST_F_SIGNAL(precedence,trap_is_second,SIGSYS)1314c99ee51aSKees Cook TEST_F_SIGNAL(precedence, trap_is_second, SIGSYS)
1315c99ee51aSKees Cook {
1316c99ee51aSKees Cook 	pid_t parent;
1317c99ee51aSKees Cook 	long ret;
1318c99ee51aSKees Cook 
1319c99ee51aSKees Cook 	parent = getppid();
1320c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1321c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1322c99ee51aSKees Cook 
1323c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1324c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
132559f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
132659f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1327c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1328c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1329c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1330c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1331c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
1332c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1333c99ee51aSKees Cook 	/* Should work just fine. */
1334c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1335c99ee51aSKees Cook 	/* getpid() should never return. */
1336c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid));
1337c99ee51aSKees Cook }
1338c99ee51aSKees Cook 
TEST_F_SIGNAL(precedence,trap_is_second_in_any_order,SIGSYS)1339c99ee51aSKees Cook TEST_F_SIGNAL(precedence, trap_is_second_in_any_order, SIGSYS)
1340c99ee51aSKees Cook {
1341c99ee51aSKees Cook 	pid_t parent;
1342c99ee51aSKees Cook 	long ret;
1343c99ee51aSKees Cook 
1344c99ee51aSKees Cook 	parent = getppid();
1345c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1346c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1347c99ee51aSKees Cook 
1348c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1349c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1350c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
1351c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
135259f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
135359f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1354c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1355c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1356c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1357c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1358c99ee51aSKees Cook 	/* Should work just fine. */
1359c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1360c99ee51aSKees Cook 	/* getpid() should never return. */
1361c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid));
1362c99ee51aSKees Cook }
1363c99ee51aSKees Cook 
TEST_F(precedence,errno_is_third)1364c99ee51aSKees Cook TEST_F(precedence, errno_is_third)
1365c99ee51aSKees Cook {
1366c99ee51aSKees Cook 	pid_t parent;
1367c99ee51aSKees Cook 	long ret;
1368c99ee51aSKees Cook 
1369c99ee51aSKees Cook 	parent = getppid();
1370c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1371c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1372c99ee51aSKees Cook 
1373c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1374c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
137559f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
137659f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1377c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1378c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1379c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1380c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1381c99ee51aSKees Cook 	/* Should work just fine. */
1382c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1383c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid));
1384c99ee51aSKees Cook }
1385c99ee51aSKees Cook 
TEST_F(precedence,errno_is_third_in_any_order)1386c99ee51aSKees Cook TEST_F(precedence, errno_is_third_in_any_order)
1387c99ee51aSKees Cook {
1388c99ee51aSKees Cook 	pid_t parent;
1389c99ee51aSKees Cook 	long ret;
1390c99ee51aSKees Cook 
1391c99ee51aSKees Cook 	parent = getppid();
1392c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1393c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1394c99ee51aSKees Cook 
139559f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
139659f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1397c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
1398c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1399c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1400c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1401c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1402c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1403c99ee51aSKees Cook 	/* Should work just fine. */
1404c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1405c99ee51aSKees Cook 	EXPECT_EQ(0, syscall(__NR_getpid));
1406c99ee51aSKees Cook }
1407c99ee51aSKees Cook 
TEST_F(precedence,trace_is_fourth)1408c99ee51aSKees Cook TEST_F(precedence, trace_is_fourth)
1409c99ee51aSKees Cook {
1410c99ee51aSKees Cook 	pid_t parent;
1411c99ee51aSKees Cook 	long ret;
1412c99ee51aSKees Cook 
1413c99ee51aSKees Cook 	parent = getppid();
1414c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1415c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1416c99ee51aSKees Cook 
1417c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1418c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
141959f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
142059f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1421c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1422c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1423c99ee51aSKees Cook 	/* Should work just fine. */
1424c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1425c99ee51aSKees Cook 	/* No ptracer */
1426c99ee51aSKees Cook 	EXPECT_EQ(-1, syscall(__NR_getpid));
1427c99ee51aSKees Cook }
1428c99ee51aSKees Cook 
TEST_F(precedence,trace_is_fourth_in_any_order)1429c99ee51aSKees Cook TEST_F(precedence, trace_is_fourth_in_any_order)
1430c99ee51aSKees Cook {
1431c99ee51aSKees Cook 	pid_t parent;
1432c99ee51aSKees Cook 	long ret;
1433c99ee51aSKees Cook 
1434c99ee51aSKees Cook 	parent = getppid();
1435c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1436c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1437c99ee51aSKees Cook 
1438c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
1439c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1440c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
1441c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
144259f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
144359f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
1444c99ee51aSKees Cook 	/* Should work just fine. */
1445c99ee51aSKees Cook 	EXPECT_EQ(parent, syscall(__NR_getppid));
1446c99ee51aSKees Cook 	/* No ptracer */
1447c99ee51aSKees Cook 	EXPECT_EQ(-1, syscall(__NR_getpid));
1448c99ee51aSKees Cook }
1449c99ee51aSKees Cook 
TEST_F(precedence,log_is_fifth)145059f5cf44STyler Hicks TEST_F(precedence, log_is_fifth)
145159f5cf44STyler Hicks {
145259f5cf44STyler Hicks 	pid_t mypid, parent;
145359f5cf44STyler Hicks 	long ret;
145459f5cf44STyler Hicks 
145559f5cf44STyler Hicks 	mypid = getpid();
145659f5cf44STyler Hicks 	parent = getppid();
145759f5cf44STyler Hicks 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
145859f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
145959f5cf44STyler Hicks 
146059f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
146159f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
146259f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
146359f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
146459f5cf44STyler Hicks 	/* Should work just fine. */
146559f5cf44STyler Hicks 	EXPECT_EQ(parent, syscall(__NR_getppid));
146659f5cf44STyler Hicks 	/* Should also work just fine */
146759f5cf44STyler Hicks 	EXPECT_EQ(mypid, syscall(__NR_getpid));
146859f5cf44STyler Hicks }
146959f5cf44STyler Hicks 
TEST_F(precedence,log_is_fifth_in_any_order)147059f5cf44STyler Hicks TEST_F(precedence, log_is_fifth_in_any_order)
147159f5cf44STyler Hicks {
147259f5cf44STyler Hicks 	pid_t mypid, parent;
147359f5cf44STyler Hicks 	long ret;
147459f5cf44STyler Hicks 
147559f5cf44STyler Hicks 	mypid = getpid();
147659f5cf44STyler Hicks 	parent = getppid();
147759f5cf44STyler Hicks 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
147859f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
147959f5cf44STyler Hicks 
148059f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
148159f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
148259f5cf44STyler Hicks 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
148359f5cf44STyler Hicks 	ASSERT_EQ(0, ret);
148459f5cf44STyler Hicks 	/* Should work just fine. */
148559f5cf44STyler Hicks 	EXPECT_EQ(parent, syscall(__NR_getppid));
148659f5cf44STyler Hicks 	/* Should also work just fine */
148759f5cf44STyler Hicks 	EXPECT_EQ(mypid, syscall(__NR_getpid));
148859f5cf44STyler Hicks }
148959f5cf44STyler Hicks 
1490c99ee51aSKees Cook #ifndef PTRACE_O_TRACESECCOMP
1491c99ee51aSKees Cook #define PTRACE_O_TRACESECCOMP	0x00000080
1492c99ee51aSKees Cook #endif
1493c99ee51aSKees Cook 
1494c99ee51aSKees Cook /* Catch the Ubuntu 12.04 value error. */
1495c99ee51aSKees Cook #if PTRACE_EVENT_SECCOMP != 7
1496c99ee51aSKees Cook #undef PTRACE_EVENT_SECCOMP
1497c99ee51aSKees Cook #endif
1498c99ee51aSKees Cook 
1499c99ee51aSKees Cook #ifndef PTRACE_EVENT_SECCOMP
1500c99ee51aSKees Cook #define PTRACE_EVENT_SECCOMP 7
1501c99ee51aSKees Cook #endif
1502c99ee51aSKees Cook 
15031e6d69c7SKees Cook #define PTRACE_EVENT_MASK(status) ((status) >> 16)
1504c99ee51aSKees Cook bool tracer_running;
tracer_stop(int sig)1505c99ee51aSKees Cook void tracer_stop(int sig)
1506c99ee51aSKees Cook {
1507c99ee51aSKees Cook 	tracer_running = false;
1508c99ee51aSKees Cook }
1509c99ee51aSKees Cook 
1510c99ee51aSKees Cook typedef void tracer_func_t(struct __test_metadata *_metadata,
1511c99ee51aSKees Cook 			   pid_t tracee, int status, void *args);
1512c99ee51aSKees Cook 
start_tracer(struct __test_metadata * _metadata,int fd,pid_t tracee,tracer_func_t tracer_func,void * args,bool ptrace_syscall)151358d0a862SKees Cook void start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
151458d0a862SKees Cook 	    tracer_func_t tracer_func, void *args, bool ptrace_syscall)
1515c99ee51aSKees Cook {
1516c99ee51aSKees Cook 	int ret = -1;
1517c99ee51aSKees Cook 	struct sigaction action = {
1518c99ee51aSKees Cook 		.sa_handler = tracer_stop,
1519c99ee51aSKees Cook 	};
1520c99ee51aSKees Cook 
1521c99ee51aSKees Cook 	/* Allow external shutdown. */
1522c99ee51aSKees Cook 	tracer_running = true;
1523c99ee51aSKees Cook 	ASSERT_EQ(0, sigaction(SIGUSR1, &action, NULL));
1524c99ee51aSKees Cook 
1525c99ee51aSKees Cook 	errno = 0;
1526c99ee51aSKees Cook 	while (ret == -1 && errno != EINVAL)
1527c99ee51aSKees Cook 		ret = ptrace(PTRACE_ATTACH, tracee, NULL, 0);
1528c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
1529c99ee51aSKees Cook 		kill(tracee, SIGKILL);
1530c99ee51aSKees Cook 	}
1531c99ee51aSKees Cook 	/* Wait for attach stop */
1532c99ee51aSKees Cook 	wait(NULL);
1533c99ee51aSKees Cook 
153458d0a862SKees Cook 	ret = ptrace(PTRACE_SETOPTIONS, tracee, NULL, ptrace_syscall ?
153558d0a862SKees Cook 						      PTRACE_O_TRACESYSGOOD :
153658d0a862SKees Cook 						      PTRACE_O_TRACESECCOMP);
1537c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
1538c99ee51aSKees Cook 		TH_LOG("Failed to set PTRACE_O_TRACESECCOMP");
1539c99ee51aSKees Cook 		kill(tracee, SIGKILL);
1540c99ee51aSKees Cook 	}
154158d0a862SKees Cook 	ret = ptrace(ptrace_syscall ? PTRACE_SYSCALL : PTRACE_CONT,
154258d0a862SKees Cook 		     tracee, NULL, 0);
154358d0a862SKees Cook 	ASSERT_EQ(0, ret);
1544c99ee51aSKees Cook 
1545c99ee51aSKees Cook 	/* Unblock the tracee */
1546c99ee51aSKees Cook 	ASSERT_EQ(1, write(fd, "A", 1));
1547c99ee51aSKees Cook 	ASSERT_EQ(0, close(fd));
1548c99ee51aSKees Cook 
1549c99ee51aSKees Cook 	/* Run until we're shut down. Must assert to stop execution. */
1550c99ee51aSKees Cook 	while (tracer_running) {
1551c99ee51aSKees Cook 		int status;
1552c99ee51aSKees Cook 
1553c99ee51aSKees Cook 		if (wait(&status) != tracee)
1554c99ee51aSKees Cook 			continue;
1555c99ee51aSKees Cook 
15561e6d69c7SKees Cook 		if (WIFSIGNALED(status)) {
15571e6d69c7SKees Cook 			/* Child caught a fatal signal. */
15581e6d69c7SKees Cook 			return;
15591e6d69c7SKees Cook 		}
15601e6d69c7SKees Cook 		if (WIFEXITED(status)) {
15611e6d69c7SKees Cook 			/* Child exited with code. */
15621e6d69c7SKees Cook 			return;
15631e6d69c7SKees Cook 		}
15641e6d69c7SKees Cook 
15651e6d69c7SKees Cook 		/* Check if we got an expected event. */
15661e6d69c7SKees Cook 		ASSERT_EQ(WIFCONTINUED(status), false);
15671e6d69c7SKees Cook 		ASSERT_EQ(WIFSTOPPED(status), true);
15681e6d69c7SKees Cook 		ASSERT_EQ(WSTOPSIG(status) & SIGTRAP, SIGTRAP) {
15691e6d69c7SKees Cook 			TH_LOG("Unexpected WSTOPSIG: %d", WSTOPSIG(status));
15701e6d69c7SKees Cook 		}
1571c99ee51aSKees Cook 
1572c99ee51aSKees Cook 		tracer_func(_metadata, tracee, status, args);
1573c99ee51aSKees Cook 
157458d0a862SKees Cook 		ret = ptrace(ptrace_syscall ? PTRACE_SYSCALL : PTRACE_CONT,
157558d0a862SKees Cook 			     tracee, NULL, 0);
1576c99ee51aSKees Cook 		ASSERT_EQ(0, ret);
1577c99ee51aSKees Cook 	}
1578c99ee51aSKees Cook 	/* Directly report the status of our test harness results. */
1579c99ee51aSKees Cook 	syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
1580c99ee51aSKees Cook }
1581c99ee51aSKees Cook 
1582c99ee51aSKees Cook /* Common tracer setup/teardown functions. */
cont_handler(int num)1583c99ee51aSKees Cook void cont_handler(int num)
1584c99ee51aSKees Cook { }
setup_trace_fixture(struct __test_metadata * _metadata,tracer_func_t func,void * args,bool ptrace_syscall)1585c99ee51aSKees Cook pid_t setup_trace_fixture(struct __test_metadata *_metadata,
158658d0a862SKees Cook 			  tracer_func_t func, void *args, bool ptrace_syscall)
1587c99ee51aSKees Cook {
1588c99ee51aSKees Cook 	char sync;
1589c99ee51aSKees Cook 	int pipefd[2];
1590c99ee51aSKees Cook 	pid_t tracer_pid;
1591c99ee51aSKees Cook 	pid_t tracee = getpid();
1592c99ee51aSKees Cook 
1593c99ee51aSKees Cook 	/* Setup a pipe for clean synchronization. */
1594c99ee51aSKees Cook 	ASSERT_EQ(0, pipe(pipefd));
1595c99ee51aSKees Cook 
1596c99ee51aSKees Cook 	/* Fork a child which we'll promote to tracer */
1597c99ee51aSKees Cook 	tracer_pid = fork();
1598c99ee51aSKees Cook 	ASSERT_LE(0, tracer_pid);
1599c99ee51aSKees Cook 	signal(SIGALRM, cont_handler);
1600c99ee51aSKees Cook 	if (tracer_pid == 0) {
1601c99ee51aSKees Cook 		close(pipefd[0]);
160258d0a862SKees Cook 		start_tracer(_metadata, pipefd[1], tracee, func, args,
160358d0a862SKees Cook 			     ptrace_syscall);
1604c99ee51aSKees Cook 		syscall(__NR_exit, 0);
1605c99ee51aSKees Cook 	}
1606c99ee51aSKees Cook 	close(pipefd[1]);
1607c99ee51aSKees Cook 	prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0);
1608c99ee51aSKees Cook 	read(pipefd[0], &sync, 1);
1609c99ee51aSKees Cook 	close(pipefd[0]);
1610c99ee51aSKees Cook 
1611c99ee51aSKees Cook 	return tracer_pid;
1612c99ee51aSKees Cook }
1613adeeec84SKees Cook 
teardown_trace_fixture(struct __test_metadata * _metadata,pid_t tracer)1614c99ee51aSKees Cook void teardown_trace_fixture(struct __test_metadata *_metadata,
1615c99ee51aSKees Cook 			    pid_t tracer)
1616c99ee51aSKees Cook {
1617c99ee51aSKees Cook 	if (tracer) {
1618c99ee51aSKees Cook 		int status;
1619c99ee51aSKees Cook 		/*
1620c99ee51aSKees Cook 		 * Extract the exit code from the other process and
1621c99ee51aSKees Cook 		 * adopt it for ourselves in case its asserts failed.
1622c99ee51aSKees Cook 		 */
1623c99ee51aSKees Cook 		ASSERT_EQ(0, kill(tracer, SIGUSR1));
1624c99ee51aSKees Cook 		ASSERT_EQ(tracer, waitpid(tracer, &status, 0));
1625c99ee51aSKees Cook 		if (WEXITSTATUS(status))
1626c99ee51aSKees Cook 			_metadata->passed = 0;
1627c99ee51aSKees Cook 	}
1628c99ee51aSKees Cook }
1629c99ee51aSKees Cook 
1630c99ee51aSKees Cook /* "poke" tracer arguments and function. */
1631c99ee51aSKees Cook struct tracer_args_poke_t {
1632c99ee51aSKees Cook 	unsigned long poke_addr;
1633c99ee51aSKees Cook };
1634c99ee51aSKees Cook 
tracer_poke(struct __test_metadata * _metadata,pid_t tracee,int status,void * args)1635c99ee51aSKees Cook void tracer_poke(struct __test_metadata *_metadata, pid_t tracee, int status,
1636c99ee51aSKees Cook 		 void *args)
1637c99ee51aSKees Cook {
1638c99ee51aSKees Cook 	int ret;
1639c99ee51aSKees Cook 	unsigned long msg;
1640c99ee51aSKees Cook 	struct tracer_args_poke_t *info = (struct tracer_args_poke_t *)args;
1641c99ee51aSKees Cook 
1642c99ee51aSKees Cook 	ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
1643c99ee51aSKees Cook 	EXPECT_EQ(0, ret);
1644c99ee51aSKees Cook 	/* If this fails, don't try to recover. */
1645c99ee51aSKees Cook 	ASSERT_EQ(0x1001, msg) {
1646c99ee51aSKees Cook 		kill(tracee, SIGKILL);
1647c99ee51aSKees Cook 	}
1648c99ee51aSKees Cook 	/*
1649c99ee51aSKees Cook 	 * Poke in the message.
1650c99ee51aSKees Cook 	 * Registers are not touched to try to keep this relatively arch
1651c99ee51aSKees Cook 	 * agnostic.
1652c99ee51aSKees Cook 	 */
1653c99ee51aSKees Cook 	ret = ptrace(PTRACE_POKEDATA, tracee, info->poke_addr, 0x1001);
1654c99ee51aSKees Cook 	EXPECT_EQ(0, ret);
1655c99ee51aSKees Cook }
1656c99ee51aSKees Cook 
FIXTURE(TRACE_poke)16571ae81d78SKees Cook FIXTURE(TRACE_poke) {
1658c99ee51aSKees Cook 	struct sock_fprog prog;
1659c99ee51aSKees Cook 	pid_t tracer;
1660c99ee51aSKees Cook 	long poked;
1661c99ee51aSKees Cook 	struct tracer_args_poke_t tracer_args;
1662c99ee51aSKees Cook };
1663c99ee51aSKees Cook 
FIXTURE_SETUP(TRACE_poke)1664c99ee51aSKees Cook FIXTURE_SETUP(TRACE_poke)
1665c99ee51aSKees Cook {
1666c99ee51aSKees Cook 	struct sock_filter filter[] = {
1667c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
1668c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
1669c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),
1670c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1001),
1671c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
1672c99ee51aSKees Cook 	};
1673c99ee51aSKees Cook 
1674c99ee51aSKees Cook 	self->poked = 0;
1675c99ee51aSKees Cook 	memset(&self->prog, 0, sizeof(self->prog));
1676c99ee51aSKees Cook 	self->prog.filter = malloc(sizeof(filter));
1677c99ee51aSKees Cook 	ASSERT_NE(NULL, self->prog.filter);
1678c99ee51aSKees Cook 	memcpy(self->prog.filter, filter, sizeof(filter));
1679c99ee51aSKees Cook 	self->prog.len = (unsigned short)ARRAY_SIZE(filter);
1680c99ee51aSKees Cook 
1681c99ee51aSKees Cook 	/* Set up tracer args. */
1682c99ee51aSKees Cook 	self->tracer_args.poke_addr = (unsigned long)&self->poked;
1683c99ee51aSKees Cook 
1684c99ee51aSKees Cook 	/* Launch tracer. */
1685c99ee51aSKees Cook 	self->tracer = setup_trace_fixture(_metadata, tracer_poke,
168658d0a862SKees Cook 					   &self->tracer_args, false);
1687c99ee51aSKees Cook }
1688c99ee51aSKees Cook 
FIXTURE_TEARDOWN(TRACE_poke)1689c99ee51aSKees Cook FIXTURE_TEARDOWN(TRACE_poke)
1690c99ee51aSKees Cook {
1691c99ee51aSKees Cook 	teardown_trace_fixture(_metadata, self->tracer);
1692c99ee51aSKees Cook 	if (self->prog.filter)
1693c99ee51aSKees Cook 		free(self->prog.filter);
1694c99ee51aSKees Cook }
1695c99ee51aSKees Cook 
TEST_F(TRACE_poke,read_has_side_effects)1696c99ee51aSKees Cook TEST_F(TRACE_poke, read_has_side_effects)
1697c99ee51aSKees Cook {
1698c99ee51aSKees Cook 	ssize_t ret;
1699c99ee51aSKees Cook 
1700c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1701c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1702c99ee51aSKees Cook 
1703c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
1704c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1705c99ee51aSKees Cook 
1706c99ee51aSKees Cook 	EXPECT_EQ(0, self->poked);
1707c99ee51aSKees Cook 	ret = read(-1, NULL, 0);
1708c99ee51aSKees Cook 	EXPECT_EQ(-1, ret);
1709c99ee51aSKees Cook 	EXPECT_EQ(0x1001, self->poked);
1710c99ee51aSKees Cook }
1711c99ee51aSKees Cook 
TEST_F(TRACE_poke,getpid_runs_normally)1712c99ee51aSKees Cook TEST_F(TRACE_poke, getpid_runs_normally)
1713c99ee51aSKees Cook {
1714c99ee51aSKees Cook 	long ret;
1715c99ee51aSKees Cook 
1716c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1717c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1718c99ee51aSKees Cook 
1719c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
1720c99ee51aSKees Cook 	ASSERT_EQ(0, ret);
1721c99ee51aSKees Cook 
1722c99ee51aSKees Cook 	EXPECT_EQ(0, self->poked);
1723c99ee51aSKees Cook 	EXPECT_NE(0, syscall(__NR_getpid));
1724c99ee51aSKees Cook 	EXPECT_EQ(0, self->poked);
1725c99ee51aSKees Cook }
1726c99ee51aSKees Cook 
1727c99ee51aSKees Cook #if defined(__x86_64__)
1728c99ee51aSKees Cook # define ARCH_REGS		struct user_regs_struct
1729a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).orig_rax
1730a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).rax
1731c99ee51aSKees Cook #elif defined(__i386__)
1732c99ee51aSKees Cook # define ARCH_REGS		struct user_regs_struct
1733a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).orig_eax
1734a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).eax
1735c99ee51aSKees Cook #elif defined(__arm__)
1736c99ee51aSKees Cook # define ARCH_REGS		struct pt_regs
1737a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).ARM_r7
1738aa8fbb80SKees Cook # ifndef PTRACE_SET_SYSCALL
1739aa8fbb80SKees Cook #  define PTRACE_SET_SYSCALL   23
1740aa8fbb80SKees Cook # endif
1741aa8fbb80SKees Cook # define SYSCALL_NUM_SET(_regs, _nr)	\
1742aa8fbb80SKees Cook 		EXPECT_EQ(0, ptrace(PTRACE_SET_SYSCALL, tracee, NULL, _nr))
1743a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).ARM_r0
1744c99ee51aSKees Cook #elif defined(__aarch64__)
1745c99ee51aSKees Cook # define ARCH_REGS		struct user_pt_regs
1746a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).regs[8]
17470dd7d685SKees Cook # ifndef NT_ARM_SYSTEM_CALL
17480dd7d685SKees Cook #  define NT_ARM_SYSTEM_CALL 0x404
17490dd7d685SKees Cook # endif
17500dd7d685SKees Cook # define SYSCALL_NUM_SET(_regs, _nr)				\
17510dd7d685SKees Cook 	do {							\
17520dd7d685SKees Cook 		struct iovec __v;				\
17530dd7d685SKees Cook 		typeof(_nr) __nr = (_nr);			\
17540dd7d685SKees Cook 		__v.iov_base = &__nr;				\
17550dd7d685SKees Cook 		__v.iov_len = sizeof(__nr);			\
17560dd7d685SKees Cook 		EXPECT_EQ(0, ptrace(PTRACE_SETREGSET, tracee,	\
17570dd7d685SKees Cook 				    NT_ARM_SYSTEM_CALL, &__v));	\
17580dd7d685SKees Cook 	} while (0)
1759a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).regs[0]
1760eb4071b9SHuacai Chen #elif defined(__loongarch__)
1761eb4071b9SHuacai Chen # define ARCH_REGS		struct user_pt_regs
1762eb4071b9SHuacai Chen # define SYSCALL_NUM(_regs)	(_regs).regs[11]
1763eb4071b9SHuacai Chen # define SYSCALL_RET(_regs)	(_regs).regs[4]
17645340627eSDavid Abdurachmanov #elif defined(__riscv) && __riscv_xlen == 64
17655340627eSDavid Abdurachmanov # define ARCH_REGS		struct user_regs_struct
1766a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).a7
1767a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).a0
1768e95a4f8cSGuo Ren #elif defined(__csky__)
1769e95a4f8cSGuo Ren # define ARCH_REGS		struct pt_regs
1770e95a4f8cSGuo Ren #  if defined(__CSKYABIV2__)
1771a6a4d784SKees Cook #   define SYSCALL_NUM(_regs)	(_regs).regs[3]
1772e95a4f8cSGuo Ren #  else
1773a6a4d784SKees Cook #   define SYSCALL_NUM(_regs)	(_regs).regs[9]
1774e95a4f8cSGuo Ren #  endif
1775a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).a0
177664e2a42bSHelge Deller #elif defined(__hppa__)
177764e2a42bSHelge Deller # define ARCH_REGS		struct user_regs_struct
1778a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).gr[20]
1779a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).gr[28]
17805d83c2b3SMichael Ellerman #elif defined(__powerpc__)
17815d83c2b3SMichael Ellerman # define ARCH_REGS		struct pt_regs
1782a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).gpr[0]
1783a6a4d784SKees Cook # define SYSCALL_RET(_regs)	(_regs).gpr[3]
178446138329SKees Cook # define SYSCALL_RET_SET(_regs, _val)				\
178546138329SKees Cook 	do {							\
178646138329SKees Cook 		typeof(_val) _result = (_val);			\
17875665bc35SNicholas Piggin 		if ((_regs.trap & 0xfff0) == 0x3000) {		\
178846138329SKees Cook 			/*					\
17895665bc35SNicholas Piggin 			 * scv 0 system call uses -ve result	\
17905665bc35SNicholas Piggin 			 * for error, so no need to adjust.	\
17915665bc35SNicholas Piggin 			 */					\
17925665bc35SNicholas Piggin 			SYSCALL_RET(_regs) = _result;		\
17935665bc35SNicholas Piggin 		} else {					\
17945665bc35SNicholas Piggin 			/*					\
17955665bc35SNicholas Piggin 			 * A syscall error is signaled by the	\
17965665bc35SNicholas Piggin 			 * CR0 SO bit and the code is stored as	\
17975665bc35SNicholas Piggin 			 * a positive value.			\
179846138329SKees Cook 			 */					\
179946138329SKees Cook 			if (_result < 0) {			\
1800f5098e34SKees Cook 				SYSCALL_RET(_regs) = -_result;	\
180146138329SKees Cook 				(_regs).ccr |= 0x10000000;	\
180246138329SKees Cook 			} else {				\
1803f5098e34SKees Cook 				SYSCALL_RET(_regs) = _result;	\
180446138329SKees Cook 				(_regs).ccr &= ~0x10000000;	\
180546138329SKees Cook 			}					\
18065665bc35SNicholas Piggin 		}						\
180746138329SKees Cook 	} while (0)
1808a39caac0SKees Cook # define SYSCALL_RET_SET_ON_PTRACE_EXIT
1809b623c4daSKees Cook #elif defined(__s390__)
1810b623c4daSKees Cook # define ARCH_REGS		s390_regs
1811a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).gprs[2]
1812f04cf78bSKees Cook # define SYSCALL_RET_SET(_regs, _val)			\
1813f04cf78bSKees Cook 		TH_LOG("Can't modify syscall return on this architecture")
18140ce105bfSMatt Redfearn #elif defined(__mips__)
181537989de7SKees Cook # include <asm/unistd_nr_n32.h>
181637989de7SKees Cook # include <asm/unistd_nr_n64.h>
181737989de7SKees Cook # include <asm/unistd_nr_o32.h>
18180ce105bfSMatt Redfearn # define ARCH_REGS		struct pt_regs
181937989de7SKees Cook # define SYSCALL_NUM(_regs)				\
182037989de7SKees Cook 	({						\
182137989de7SKees Cook 		typeof((_regs).regs[2]) _nr;		\
182237989de7SKees Cook 		if ((_regs).regs[2] == __NR_O32_Linux)	\
182337989de7SKees Cook 			_nr = (_regs).regs[4];		\
182437989de7SKees Cook 		else					\
182537989de7SKees Cook 			_nr = (_regs).regs[2];		\
182637989de7SKees Cook 		_nr;					\
182737989de7SKees Cook 	})
1828a084a6cbSKees Cook # define SYSCALL_NUM_SET(_regs, _nr)			\
1829a084a6cbSKees Cook 	do {						\
1830a084a6cbSKees Cook 		if ((_regs).regs[2] == __NR_O32_Linux)	\
1831a084a6cbSKees Cook 			(_regs).regs[4] = _nr;		\
1832a084a6cbSKees Cook 		else					\
1833a084a6cbSKees Cook 			(_regs).regs[2] = _nr;		\
1834a084a6cbSKees Cook 	} while (0)
1835f04cf78bSKees Cook # define SYSCALL_RET_SET(_regs, _val)			\
1836f04cf78bSKees Cook 		TH_LOG("Can't modify syscall return on this architecture")
1837768877beSMax Filippov #elif defined(__xtensa__)
1838768877beSMax Filippov # define ARCH_REGS		struct user_pt_regs
1839a6a4d784SKees Cook # define SYSCALL_NUM(_regs)	(_regs).syscall
1840768877beSMax Filippov /*
1841768877beSMax Filippov  * On xtensa syscall return value is in the register
1842768877beSMax Filippov  * a2 of the current window which is not fixed.
1843768877beSMax Filippov  */
1844a6a4d784SKees Cook #define SYSCALL_RET(_regs)	(_regs).a[(_regs).windowbase * 4 + 2]
18450bb605c2SMichael Karcher #elif defined(__sh__)
18460bb605c2SMichael Karcher # define ARCH_REGS		struct pt_regs
18474c222f31SKees Cook # define SYSCALL_NUM(_regs)	(_regs).regs[3]
18484c222f31SKees Cook # define SYSCALL_RET(_regs)	(_regs).regs[0]
1849be6c50d3SMichael Schmitz #elif defined(__mc68000__)
1850be6c50d3SMichael Schmitz # define ARCH_REGS		struct user_regs_struct
1851be6c50d3SMichael Schmitz # define SYSCALL_NUM(_regs)	(_regs).orig_d0
1852be6c50d3SMichael Schmitz # define SYSCALL_RET(_regs)	(_regs).d0
1853c99ee51aSKees Cook #else
1854c99ee51aSKees Cook # error "Do not know how to find your architecture's registers and syscalls"
1855c99ee51aSKees Cook #endif
1856c99ee51aSKees Cook 
185731c36eb8SKees Cook /*
185831c36eb8SKees Cook  * Most architectures can change the syscall by just updating the
185931c36eb8SKees Cook  * associated register. This is the default if not defined above.
186031c36eb8SKees Cook  */
186131c36eb8SKees Cook #ifndef SYSCALL_NUM_SET
186231c36eb8SKees Cook # define SYSCALL_NUM_SET(_regs, _nr)		\
186331c36eb8SKees Cook 	do {					\
186431c36eb8SKees Cook 		SYSCALL_NUM(_regs) = (_nr);	\
186531c36eb8SKees Cook 	} while (0)
186631c36eb8SKees Cook #endif
1867f04cf78bSKees Cook /*
1868f04cf78bSKees Cook  * Most architectures can change the syscall return value by just
1869f04cf78bSKees Cook  * writing to the SYSCALL_RET register. This is the default if not
1870f04cf78bSKees Cook  * defined above. If an architecture cannot set the return value
1871f04cf78bSKees Cook  * (for example when the syscall and return value register is
1872f04cf78bSKees Cook  * shared), report it with TH_LOG() in an arch-specific definition
1873f04cf78bSKees Cook  * of SYSCALL_RET_SET() above, and leave SYSCALL_RET undefined.
1874f04cf78bSKees Cook  */
1875f04cf78bSKees Cook #if !defined(SYSCALL_RET) && !defined(SYSCALL_RET_SET)
1876f04cf78bSKees Cook # error "One of SYSCALL_RET or SYSCALL_RET_SET is needed for this arch"
1877f04cf78bSKees Cook #endif
1878f04cf78bSKees Cook #ifndef SYSCALL_RET_SET
1879f04cf78bSKees Cook # define SYSCALL_RET_SET(_regs, _val)		\
1880f04cf78bSKees Cook 	do {					\
1881f04cf78bSKees Cook 		SYSCALL_RET(_regs) = (_val);	\
1882f04cf78bSKees Cook 	} while (0)
1883f04cf78bSKees Cook #endif
188431c36eb8SKees Cook 
1885a33b2d03SKees Cook /* When the syscall return can't be changed, stub out the tests for it. */
1886f04cf78bSKees Cook #ifndef SYSCALL_RET
1887a33b2d03SKees Cook # define EXPECT_SYSCALL_RETURN(val, action)	EXPECT_EQ(-1, action)
1888a33b2d03SKees Cook #else
1889ed5f1326SKees Cook # define EXPECT_SYSCALL_RETURN(val, action)		\
1890ed5f1326SKees Cook 	do {						\
1891ed5f1326SKees Cook 		errno = 0;				\
1892ed5f1326SKees Cook 		if (val < 0) {				\
1893ed5f1326SKees Cook 			EXPECT_EQ(-1, action);		\
1894ed5f1326SKees Cook 			EXPECT_EQ(-(val), errno);	\
1895ed5f1326SKees Cook 		} else {				\
1896ed5f1326SKees Cook 			EXPECT_EQ(val, action);		\
1897ed5f1326SKees Cook 		}					\
1898ed5f1326SKees Cook 	} while (0)
1899a33b2d03SKees Cook #endif
1900a33b2d03SKees Cook 
1901fdbaa798SKees Cook /*
1902a39caac0SKees Cook  * Some architectures (e.g. powerpc) can only set syscall
1903a39caac0SKees Cook  * return values on syscall exit during ptrace.
1904a39caac0SKees Cook  */
1905a39caac0SKees Cook const bool ptrace_entry_set_syscall_nr = true;
1906a39caac0SKees Cook const bool ptrace_entry_set_syscall_ret =
1907a39caac0SKees Cook #ifndef SYSCALL_RET_SET_ON_PTRACE_EXIT
1908a39caac0SKees Cook 	true;
1909a39caac0SKees Cook #else
1910a39caac0SKees Cook 	false;
1911a39caac0SKees Cook #endif
1912a39caac0SKees Cook 
1913a39caac0SKees Cook /*
1914fdbaa798SKees Cook  * Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
19154a0b8807SMickaël Salaün  * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).
19164a0b8807SMickaël Salaün  */
1917be6c50d3SMichael Schmitz #if defined(__x86_64__) || defined(__i386__) || defined(__mips__) || defined(__mc68000__)
1918fdbaa798SKees Cook # define ARCH_GETREGS(_regs)	ptrace(PTRACE_GETREGS, tracee, 0, &(_regs))
1919fdbaa798SKees Cook # define ARCH_SETREGS(_regs)	ptrace(PTRACE_SETREGS, tracee, 0, &(_regs))
1920dc2ad165SKees Cook #else
1921dc2ad165SKees Cook # define ARCH_GETREGS(_regs)	({					\
1922dc2ad165SKees Cook 		struct iovec __v;					\
1923dc2ad165SKees Cook 		__v.iov_base = &(_regs);				\
1924dc2ad165SKees Cook 		__v.iov_len = sizeof(_regs);				\
1925dc2ad165SKees Cook 		ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &__v);	\
1926dc2ad165SKees Cook 	})
1927dc2ad165SKees Cook # define ARCH_SETREGS(_regs)	({					\
1928dc2ad165SKees Cook 		struct iovec __v;					\
1929dc2ad165SKees Cook 		__v.iov_base = &(_regs);				\
1930dc2ad165SKees Cook 		__v.iov_len = sizeof(_regs);				\
1931dc2ad165SKees Cook 		ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &__v);	\
1932dc2ad165SKees Cook 	})
19334a0b8807SMickaël Salaün #endif
19344a0b8807SMickaël Salaün 
1935c99ee51aSKees Cook /* Architecture-specific syscall fetching routine. */
get_syscall(struct __test_metadata * _metadata,pid_t tracee)1936c99ee51aSKees Cook int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
1937c99ee51aSKees Cook {
1938c99ee51aSKees Cook 	ARCH_REGS regs;
1939dc2ad165SKees Cook 
1940fdbaa798SKees Cook 	EXPECT_EQ(0, ARCH_GETREGS(regs)) {
19414a0b8807SMickaël Salaün 		return -1;
19424a0b8807SMickaël Salaün 	}
1943c99ee51aSKees Cook 
1944a6a4d784SKees Cook 	return SYSCALL_NUM(regs);
1945c99ee51aSKees Cook }
1946c99ee51aSKees Cook 
1947c99ee51aSKees Cook /* Architecture-specific syscall changing routine. */
__change_syscall(struct __test_metadata * _metadata,pid_t tracee,long * syscall,long * ret)1948bef71f86SKees Cook void __change_syscall(struct __test_metadata *_metadata,
1949bef71f86SKees Cook 		    pid_t tracee, long *syscall, long *ret)
1950c99ee51aSKees Cook {
1951e4e8e5d2SKees Cook 	ARCH_REGS orig, regs;
1952dc2ad165SKees Cook 
1953bef71f86SKees Cook 	/* Do not get/set registers if we have nothing to do. */
1954bef71f86SKees Cook 	if (!syscall && !ret)
1955bef71f86SKees Cook 		return;
1956bef71f86SKees Cook 
1957fdbaa798SKees Cook 	EXPECT_EQ(0, ARCH_GETREGS(regs)) {
1958fdbaa798SKees Cook 		return;
1959fdbaa798SKees Cook 	}
1960e4e8e5d2SKees Cook 	orig = regs;
1961c99ee51aSKees Cook 
1962bef71f86SKees Cook 	if (syscall)
1963bef71f86SKees Cook 		SYSCALL_NUM_SET(regs, *syscall);
1964c99ee51aSKees Cook 
1965bef71f86SKees Cook 	if (ret)
1966bef71f86SKees Cook 		SYSCALL_RET_SET(regs, *ret);
1967c99ee51aSKees Cook 
196878f26627SKees Cook 	/* Flush any register changes made. */
1969e4e8e5d2SKees Cook 	if (memcmp(&orig, &regs, sizeof(orig)) != 0)
1970fdbaa798SKees Cook 		EXPECT_EQ(0, ARCH_SETREGS(regs));
1971c99ee51aSKees Cook }
1972c99ee51aSKees Cook 
1973bef71f86SKees Cook /* Change only syscall number. */
change_syscall_nr(struct __test_metadata * _metadata,pid_t tracee,long syscall)1974bef71f86SKees Cook void change_syscall_nr(struct __test_metadata *_metadata,
1975bef71f86SKees Cook 		       pid_t tracee, long syscall)
1976bef71f86SKees Cook {
1977bef71f86SKees Cook 	__change_syscall(_metadata, tracee, &syscall, NULL);
1978bef71f86SKees Cook }
1979bef71f86SKees Cook 
1980bef71f86SKees Cook /* Change syscall return value (and set syscall number to -1). */
change_syscall_ret(struct __test_metadata * _metadata,pid_t tracee,long ret)1981bef71f86SKees Cook void change_syscall_ret(struct __test_metadata *_metadata,
1982bef71f86SKees Cook 			pid_t tracee, long ret)
1983bef71f86SKees Cook {
1984bef71f86SKees Cook 	long syscall = -1;
1985bef71f86SKees Cook 
1986bef71f86SKees Cook 	__change_syscall(_metadata, tracee, &syscall, &ret);
1987bef71f86SKees Cook }
1988bef71f86SKees Cook 
tracer_seccomp(struct __test_metadata * _metadata,pid_t tracee,int status,void * args)1989adeeec84SKees Cook void tracer_seccomp(struct __test_metadata *_metadata, pid_t tracee,
1990c99ee51aSKees Cook 		    int status, void *args)
1991c99ee51aSKees Cook {
1992c99ee51aSKees Cook 	int ret;
1993c99ee51aSKees Cook 	unsigned long msg;
1994c99ee51aSKees Cook 
19951e6d69c7SKees Cook 	EXPECT_EQ(PTRACE_EVENT_MASK(status), PTRACE_EVENT_SECCOMP) {
19961e6d69c7SKees Cook 		TH_LOG("Unexpected ptrace event: %d", PTRACE_EVENT_MASK(status));
19971e6d69c7SKees Cook 		return;
19981e6d69c7SKees Cook 	}
19991e6d69c7SKees Cook 
2000c99ee51aSKees Cook 	/* Make sure we got the right message. */
2001c99ee51aSKees Cook 	ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
2002c99ee51aSKees Cook 	EXPECT_EQ(0, ret);
2003c99ee51aSKees Cook 
2004b623c4daSKees Cook 	/* Validate and take action on expected syscalls. */
2005c99ee51aSKees Cook 	switch (msg) {
2006c99ee51aSKees Cook 	case 0x1002:
2007c99ee51aSKees Cook 		/* change getpid to getppid. */
2008b623c4daSKees Cook 		EXPECT_EQ(__NR_getpid, get_syscall(_metadata, tracee));
2009bef71f86SKees Cook 		change_syscall_nr(_metadata, tracee, __NR_getppid);
2010c99ee51aSKees Cook 		break;
2011c99ee51aSKees Cook 	case 0x1003:
2012ed5f1326SKees Cook 		/* skip gettid with valid return code. */
2013b623c4daSKees Cook 		EXPECT_EQ(__NR_gettid, get_syscall(_metadata, tracee));
2014bef71f86SKees Cook 		change_syscall_ret(_metadata, tracee, 45000);
2015c99ee51aSKees Cook 		break;
2016c99ee51aSKees Cook 	case 0x1004:
2017ed5f1326SKees Cook 		/* skip openat with error. */
2018ed5f1326SKees Cook 		EXPECT_EQ(__NR_openat, get_syscall(_metadata, tracee));
2019bef71f86SKees Cook 		change_syscall_ret(_metadata, tracee, -ESRCH);
2020ed5f1326SKees Cook 		break;
2021ed5f1326SKees Cook 	case 0x1005:
2022c99ee51aSKees Cook 		/* do nothing (allow getppid) */
2023b623c4daSKees Cook 		EXPECT_EQ(__NR_getppid, get_syscall(_metadata, tracee));
2024c99ee51aSKees Cook 		break;
2025c99ee51aSKees Cook 	default:
2026c99ee51aSKees Cook 		EXPECT_EQ(0, msg) {
2027c99ee51aSKees Cook 			TH_LOG("Unknown PTRACE_GETEVENTMSG: 0x%lx", msg);
2028c99ee51aSKees Cook 			kill(tracee, SIGKILL);
2029c99ee51aSKees Cook 		}
2030c99ee51aSKees Cook 	}
2031c99ee51aSKees Cook 
2032c99ee51aSKees Cook }
2033c99ee51aSKees Cook 
FIXTURE(TRACE_syscall)203471c87fbeSKees Cook FIXTURE(TRACE_syscall) {
203571c87fbeSKees Cook 	struct sock_fprog prog;
203671c87fbeSKees Cook 	pid_t tracer, mytid, mypid, parent;
203771c87fbeSKees Cook 	long syscall_nr;
203871c87fbeSKees Cook };
203971c87fbeSKees Cook 
tracer_ptrace(struct __test_metadata * _metadata,pid_t tracee,int status,void * args)204058d0a862SKees Cook void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
204158d0a862SKees Cook 		   int status, void *args)
204258d0a862SKees Cook {
204371c87fbeSKees Cook 	int ret;
204458d0a862SKees Cook 	unsigned long msg;
204558d0a862SKees Cook 	static bool entry;
2046bef71f86SKees Cook 	long syscall_nr_val, syscall_ret_val;
2047bef71f86SKees Cook 	long *syscall_nr = NULL, *syscall_ret = NULL;
204871c87fbeSKees Cook 	FIXTURE_DATA(TRACE_syscall) *self = args;
204958d0a862SKees Cook 
20501e6d69c7SKees Cook 	EXPECT_EQ(WSTOPSIG(status) & 0x80, 0x80) {
20511e6d69c7SKees Cook 		TH_LOG("Unexpected WSTOPSIG: %d", WSTOPSIG(status));
20521e6d69c7SKees Cook 		return;
20531e6d69c7SKees Cook 	}
20541e6d69c7SKees Cook 
2055201766a2SElvira Khabirova 	/*
2056201766a2SElvira Khabirova 	 * The traditional way to tell PTRACE_SYSCALL entry/exit
2057201766a2SElvira Khabirova 	 * is by counting.
2058201766a2SElvira Khabirova 	 */
2059201766a2SElvira Khabirova 	entry = !entry;
2060201766a2SElvira Khabirova 
2061201766a2SElvira Khabirova 	/* Make sure we got an appropriate message. */
206258d0a862SKees Cook 	ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
206358d0a862SKees Cook 	EXPECT_EQ(0, ret);
2064201766a2SElvira Khabirova 	EXPECT_EQ(entry ? PTRACE_EVENTMSG_SYSCALL_ENTRY
2065201766a2SElvira Khabirova 			: PTRACE_EVENTMSG_SYSCALL_EXIT, msg);
206658d0a862SKees Cook 
206771c87fbeSKees Cook 	/*
206871c87fbeSKees Cook 	 * Some architectures only support setting return values during
206971c87fbeSKees Cook 	 * syscall exit under ptrace, and on exit the syscall number may
207071c87fbeSKees Cook 	 * no longer be available. Therefore, save the initial sycall
207171c87fbeSKees Cook 	 * number here, so it can be examined during both entry and exit
207271c87fbeSKees Cook 	 * phases.
207371c87fbeSKees Cook 	 */
207471c87fbeSKees Cook 	if (entry)
207571c87fbeSKees Cook 		self->syscall_nr = get_syscall(_metadata, tracee);
207658d0a862SKees Cook 
2077a39caac0SKees Cook 	/*
2078a39caac0SKees Cook 	 * Depending on the architecture's syscall setting abilities, we
2079a39caac0SKees Cook 	 * pick which things to set during this phase (entry or exit).
2080a39caac0SKees Cook 	 */
2081a39caac0SKees Cook 	if (entry == ptrace_entry_set_syscall_nr)
2082bef71f86SKees Cook 		syscall_nr = &syscall_nr_val;
2083a39caac0SKees Cook 	if (entry == ptrace_entry_set_syscall_ret)
2084bef71f86SKees Cook 		syscall_ret = &syscall_ret_val;
2085bef71f86SKees Cook 
2086bef71f86SKees Cook 	/* Now handle the actual rewriting cases. */
208771c87fbeSKees Cook 	switch (self->syscall_nr) {
208871c87fbeSKees Cook 	case __NR_getpid:
2089bef71f86SKees Cook 		syscall_nr_val = __NR_getppid;
2090bef71f86SKees Cook 		/* Never change syscall return for this case. */
2091bef71f86SKees Cook 		syscall_ret = NULL;
209271c87fbeSKees Cook 		break;
209371c87fbeSKees Cook 	case __NR_gettid:
2094bef71f86SKees Cook 		syscall_nr_val = -1;
2095bef71f86SKees Cook 		syscall_ret_val = 45000;
209671c87fbeSKees Cook 		break;
209771c87fbeSKees Cook 	case __NR_openat:
2098bef71f86SKees Cook 		syscall_nr_val = -1;
2099bef71f86SKees Cook 		syscall_ret_val = -ESRCH;
210071c87fbeSKees Cook 		break;
2101bef71f86SKees Cook 	default:
2102bef71f86SKees Cook 		/* Unhandled, do nothing. */
2103bef71f86SKees Cook 		return;
210458d0a862SKees Cook 	}
2105bef71f86SKees Cook 
2106bef71f86SKees Cook 	__change_syscall(_metadata, tracee, syscall_nr, syscall_ret);
210771c87fbeSKees Cook }
2108c99ee51aSKees Cook 
FIXTURE_VARIANT(TRACE_syscall)2109adeeec84SKees Cook FIXTURE_VARIANT(TRACE_syscall) {
2110adeeec84SKees Cook 	/*
2111adeeec84SKees Cook 	 * All of the SECCOMP_RET_TRACE behaviors can be tested with either
2112adeeec84SKees Cook 	 * SECCOMP_RET_TRACE+PTRACE_CONT or plain ptrace()+PTRACE_SYSCALL.
2113adeeec84SKees Cook 	 * This indicates if we should use SECCOMP_RET_TRACE (false), or
2114adeeec84SKees Cook 	 * ptrace (true).
2115adeeec84SKees Cook 	 */
2116adeeec84SKees Cook 	bool use_ptrace;
2117adeeec84SKees Cook };
2118adeeec84SKees Cook 
FIXTURE_VARIANT_ADD(TRACE_syscall,ptrace)2119adeeec84SKees Cook FIXTURE_VARIANT_ADD(TRACE_syscall, ptrace) {
2120adeeec84SKees Cook 	.use_ptrace = true,
2121adeeec84SKees Cook };
2122adeeec84SKees Cook 
FIXTURE_VARIANT_ADD(TRACE_syscall,seccomp)2123adeeec84SKees Cook FIXTURE_VARIANT_ADD(TRACE_syscall, seccomp) {
2124adeeec84SKees Cook 	.use_ptrace = false,
2125adeeec84SKees Cook };
2126adeeec84SKees Cook 
FIXTURE_SETUP(TRACE_syscall)2127c99ee51aSKees Cook FIXTURE_SETUP(TRACE_syscall)
2128c99ee51aSKees Cook {
2129c99ee51aSKees Cook 	struct sock_filter filter[] = {
2130c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
2131c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
2132c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
2133c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1002),
2134c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_gettid, 0, 1),
2135c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1003),
2136ed5f1326SKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_openat, 0, 1),
2137c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1004),
2138ed5f1326SKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
2139ed5f1326SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1005),
2140c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2141c99ee51aSKees Cook 	};
2142adeeec84SKees Cook 	struct sock_fprog prog = {
2143adeeec84SKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
2144adeeec84SKees Cook 		.filter = filter,
2145adeeec84SKees Cook 	};
2146adeeec84SKees Cook 	long ret;
2147c99ee51aSKees Cook 
2148c99ee51aSKees Cook 	/* Prepare some testable syscall results. */
2149c99ee51aSKees Cook 	self->mytid = syscall(__NR_gettid);
2150c99ee51aSKees Cook 	ASSERT_GT(self->mytid, 0);
2151c99ee51aSKees Cook 	ASSERT_NE(self->mytid, 1) {
2152c99ee51aSKees Cook 		TH_LOG("Running this test as init is not supported. :)");
2153c99ee51aSKees Cook 	}
2154c99ee51aSKees Cook 
2155c99ee51aSKees Cook 	self->mypid = getpid();
2156c99ee51aSKees Cook 	ASSERT_GT(self->mypid, 0);
2157c99ee51aSKees Cook 	ASSERT_EQ(self->mytid, self->mypid);
2158c99ee51aSKees Cook 
2159c99ee51aSKees Cook 	self->parent = getppid();
2160c99ee51aSKees Cook 	ASSERT_GT(self->parent, 0);
2161c99ee51aSKees Cook 	ASSERT_NE(self->parent, self->mypid);
2162c99ee51aSKees Cook 
2163c99ee51aSKees Cook 	/* Launch tracer. */
2164adeeec84SKees Cook 	self->tracer = setup_trace_fixture(_metadata,
2165adeeec84SKees Cook 					   variant->use_ptrace ? tracer_ptrace
2166adeeec84SKees Cook 							       : tracer_seccomp,
216771c87fbeSKees Cook 					   self, variant->use_ptrace);
2168adeeec84SKees Cook 
2169adeeec84SKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
2170adeeec84SKees Cook 	ASSERT_EQ(0, ret);
2171adeeec84SKees Cook 
21721e6d69c7SKees Cook 	/* Do not install seccomp rewrite filters, as we'll use ptrace instead. */
2173adeeec84SKees Cook 	if (variant->use_ptrace)
2174adeeec84SKees Cook 		return;
2175adeeec84SKees Cook 
2176adeeec84SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
2177adeeec84SKees Cook 	ASSERT_EQ(0, ret);
2178c99ee51aSKees Cook }
2179c99ee51aSKees Cook 
FIXTURE_TEARDOWN(TRACE_syscall)2180c99ee51aSKees Cook FIXTURE_TEARDOWN(TRACE_syscall)
2181c99ee51aSKees Cook {
2182c99ee51aSKees Cook 	teardown_trace_fixture(_metadata, self->tracer);
2183c99ee51aSKees Cook }
2184c99ee51aSKees Cook 
TEST(negative_ENOSYS)218511eb004eSKees Cook TEST(negative_ENOSYS)
2186a33b2d03SKees Cook {
2187fbc5d382SKees Cook #if defined(__arm__)
2188fbc5d382SKees Cook 	SKIP(return, "arm32 does not support calling syscall -1");
2189fbc5d382SKees Cook #endif
219011eb004eSKees Cook 	/*
219111eb004eSKees Cook 	 * There should be no difference between an "internal" skip
219211eb004eSKees Cook 	 * and userspace asking for syscall "-1".
219311eb004eSKees Cook 	 */
219411eb004eSKees Cook 	errno = 0;
219511eb004eSKees Cook 	EXPECT_EQ(-1, syscall(-1));
219611eb004eSKees Cook 	EXPECT_EQ(errno, ENOSYS);
219711eb004eSKees Cook 	/* And no difference for "still not valid but not -1". */
219811eb004eSKees Cook 	errno = 0;
219911eb004eSKees Cook 	EXPECT_EQ(-1, syscall(-101));
220011eb004eSKees Cook 	EXPECT_EQ(errno, ENOSYS);
2201a33b2d03SKees Cook }
2202a33b2d03SKees Cook 
TEST_F(TRACE_syscall,negative_ENOSYS)220311eb004eSKees Cook TEST_F(TRACE_syscall, negative_ENOSYS)
2204a33b2d03SKees Cook {
220511eb004eSKees Cook 	negative_ENOSYS(_metadata);
2206a33b2d03SKees Cook }
2207a33b2d03SKees Cook 
TEST_F(TRACE_syscall,syscall_allowed)2208c99ee51aSKees Cook TEST_F(TRACE_syscall, syscall_allowed)
2209c99ee51aSKees Cook {
2210c99ee51aSKees Cook 	/* getppid works as expected (no changes). */
2211c99ee51aSKees Cook 	EXPECT_EQ(self->parent, syscall(__NR_getppid));
2212c99ee51aSKees Cook 	EXPECT_NE(self->mypid, syscall(__NR_getppid));
2213c99ee51aSKees Cook }
2214c99ee51aSKees Cook 
TEST_F(TRACE_syscall,syscall_redirected)2215c99ee51aSKees Cook TEST_F(TRACE_syscall, syscall_redirected)
2216c99ee51aSKees Cook {
2217c99ee51aSKees Cook 	/* getpid has been redirected to getppid as expected. */
2218c99ee51aSKees Cook 	EXPECT_EQ(self->parent, syscall(__NR_getpid));
2219c99ee51aSKees Cook 	EXPECT_NE(self->mypid, syscall(__NR_getpid));
2220c99ee51aSKees Cook }
2221c99ee51aSKees Cook 
TEST_F(TRACE_syscall,syscall_errno)2222ed5f1326SKees Cook TEST_F(TRACE_syscall, syscall_errno)
2223ed5f1326SKees Cook {
2224adeeec84SKees Cook 	/* Tracer should skip the open syscall, resulting in ESRCH. */
2225ed5f1326SKees Cook 	EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
2226ed5f1326SKees Cook }
2227ed5f1326SKees Cook 
TEST_F(TRACE_syscall,syscall_faked)2228ed5f1326SKees Cook TEST_F(TRACE_syscall, syscall_faked)
2229c99ee51aSKees Cook {
2230adeeec84SKees Cook 	/* Tracer skips the gettid syscall and store altered return value. */
2231ed5f1326SKees Cook 	EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
2232c99ee51aSKees Cook }
2233c99ee51aSKees Cook 
TEST_F_SIGNAL(TRACE_syscall,kill_immediate,SIGSYS)22341e6d69c7SKees Cook TEST_F_SIGNAL(TRACE_syscall, kill_immediate, SIGSYS)
22351e6d69c7SKees Cook {
22361e6d69c7SKees Cook 	struct sock_filter filter[] = {
22371e6d69c7SKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
22381e6d69c7SKees Cook 			offsetof(struct seccomp_data, nr)),
22391e6d69c7SKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_mknodat, 0, 1),
22401e6d69c7SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD),
22411e6d69c7SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
22421e6d69c7SKees Cook 	};
22431e6d69c7SKees Cook 	struct sock_fprog prog = {
22441e6d69c7SKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
22451e6d69c7SKees Cook 		.filter = filter,
22461e6d69c7SKees Cook 	};
22471e6d69c7SKees Cook 	long ret;
22481e6d69c7SKees Cook 
22491e6d69c7SKees Cook 	/* Install "kill on mknodat" filter. */
22501e6d69c7SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
22511e6d69c7SKees Cook 	ASSERT_EQ(0, ret);
22521e6d69c7SKees Cook 
22531e6d69c7SKees Cook 	/* This should immediately die with SIGSYS, regardless of tracer. */
22541e6d69c7SKees Cook 	EXPECT_EQ(-1, syscall(__NR_mknodat, -1, NULL, 0, 0));
22551e6d69c7SKees Cook }
22561e6d69c7SKees Cook 
TEST_F(TRACE_syscall,skip_after)2257adeeec84SKees Cook TEST_F(TRACE_syscall, skip_after)
225858d0a862SKees Cook {
225958d0a862SKees Cook 	struct sock_filter filter[] = {
226058d0a862SKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
226158d0a862SKees Cook 			offsetof(struct seccomp_data, nr)),
226258d0a862SKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
226358d0a862SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | EPERM),
226458d0a862SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
226558d0a862SKees Cook 	};
226658d0a862SKees Cook 	struct sock_fprog prog = {
226758d0a862SKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
226858d0a862SKees Cook 		.filter = filter,
226958d0a862SKees Cook 	};
227058d0a862SKees Cook 	long ret;
227158d0a862SKees Cook 
2272adeeec84SKees Cook 	/* Install additional "errno on getppid" filter. */
227358d0a862SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
227458d0a862SKees Cook 	ASSERT_EQ(0, ret);
227558d0a862SKees Cook 
227658d0a862SKees Cook 	/* Tracer will redirect getpid to getppid, and we should see EPERM. */
2277a33b2d03SKees Cook 	errno = 0;
227858d0a862SKees Cook 	EXPECT_EQ(-1, syscall(__NR_getpid));
227958d0a862SKees Cook 	EXPECT_EQ(EPERM, errno);
228058d0a862SKees Cook }
228158d0a862SKees Cook 
TEST_F_SIGNAL(TRACE_syscall,kill_after,SIGSYS)2282adeeec84SKees Cook TEST_F_SIGNAL(TRACE_syscall, kill_after, SIGSYS)
228358d0a862SKees Cook {
228458d0a862SKees Cook 	struct sock_filter filter[] = {
228558d0a862SKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
228658d0a862SKees Cook 			offsetof(struct seccomp_data, nr)),
228758d0a862SKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
228858d0a862SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
228958d0a862SKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
229058d0a862SKees Cook 	};
229158d0a862SKees Cook 	struct sock_fprog prog = {
229258d0a862SKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
229358d0a862SKees Cook 		.filter = filter,
229458d0a862SKees Cook 	};
229558d0a862SKees Cook 	long ret;
229658d0a862SKees Cook 
2297adeeec84SKees Cook 	/* Install additional "death on getppid" filter. */
229858d0a862SKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
229958d0a862SKees Cook 	ASSERT_EQ(0, ret);
230058d0a862SKees Cook 
230158d0a862SKees Cook 	/* Tracer will redirect getpid to getppid, and we should die. */
230258d0a862SKees Cook 	EXPECT_NE(self->mypid, syscall(__NR_getpid));
230358d0a862SKees Cook }
230458d0a862SKees Cook 
TEST(seccomp_syscall)2305c99ee51aSKees Cook TEST(seccomp_syscall)
2306c99ee51aSKees Cook {
2307c99ee51aSKees Cook 	struct sock_filter filter[] = {
2308c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2309c99ee51aSKees Cook 	};
2310c99ee51aSKees Cook 	struct sock_fprog prog = {
2311c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
2312c99ee51aSKees Cook 		.filter = filter,
2313c99ee51aSKees Cook 	};
2314c99ee51aSKees Cook 	long ret;
2315c99ee51aSKees Cook 
2316c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
2317c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2318c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2319c99ee51aSKees Cook 	}
2320c99ee51aSKees Cook 
2321c99ee51aSKees Cook 	/* Reject insane operation. */
2322c99ee51aSKees Cook 	ret = seccomp(-1, 0, &prog);
2323b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2324b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2325b623c4daSKees Cook 	}
2326c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno) {
2327c99ee51aSKees Cook 		TH_LOG("Did not reject crazy op value!");
2328c99ee51aSKees Cook 	}
2329c99ee51aSKees Cook 
2330c99ee51aSKees Cook 	/* Reject strict with flags or pointer. */
2331c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_STRICT, -1, NULL);
2332c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno) {
2333c99ee51aSKees Cook 		TH_LOG("Did not reject mode strict with flags!");
2334c99ee51aSKees Cook 	}
2335c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, &prog);
2336c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno) {
2337c99ee51aSKees Cook 		TH_LOG("Did not reject mode strict with uargs!");
2338c99ee51aSKees Cook 	}
2339c99ee51aSKees Cook 
2340c99ee51aSKees Cook 	/* Reject insane args for filter. */
2341c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, -1, &prog);
2342c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno) {
2343c99ee51aSKees Cook 		TH_LOG("Did not reject crazy filter flags!");
2344c99ee51aSKees Cook 	}
2345c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, NULL);
2346c99ee51aSKees Cook 	EXPECT_EQ(EFAULT, errno) {
2347c99ee51aSKees Cook 		TH_LOG("Did not reject NULL filter!");
2348c99ee51aSKees Cook 	}
2349c99ee51aSKees Cook 
2350c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
2351c99ee51aSKees Cook 	EXPECT_EQ(0, errno) {
2352c99ee51aSKees Cook 		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER: %s",
2353c99ee51aSKees Cook 			strerror(errno));
2354c99ee51aSKees Cook 	}
2355c99ee51aSKees Cook }
2356c99ee51aSKees Cook 
TEST(seccomp_syscall_mode_lock)2357c99ee51aSKees Cook TEST(seccomp_syscall_mode_lock)
2358c99ee51aSKees Cook {
2359c99ee51aSKees Cook 	struct sock_filter filter[] = {
2360c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2361c99ee51aSKees Cook 	};
2362c99ee51aSKees Cook 	struct sock_fprog prog = {
2363c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
2364c99ee51aSKees Cook 		.filter = filter,
2365c99ee51aSKees Cook 	};
2366c99ee51aSKees Cook 	long ret;
2367c99ee51aSKees Cook 
2368c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
2369c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2370c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2371c99ee51aSKees Cook 	}
2372c99ee51aSKees Cook 
2373c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
2374b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2375b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2376b623c4daSKees Cook 	}
2377c99ee51aSKees Cook 	EXPECT_EQ(0, ret) {
2378c99ee51aSKees Cook 		TH_LOG("Could not install filter!");
2379c99ee51aSKees Cook 	}
2380c99ee51aSKees Cook 
2381c99ee51aSKees Cook 	/* Make sure neither entry point will switch to strict. */
2382c99ee51aSKees Cook 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0);
2383c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno) {
2384c99ee51aSKees Cook 		TH_LOG("Switched to mode strict!");
2385c99ee51aSKees Cook 	}
2386c99ee51aSKees Cook 
2387c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL);
2388c99ee51aSKees Cook 	EXPECT_EQ(EINVAL, errno) {
2389c99ee51aSKees Cook 		TH_LOG("Switched to mode strict!");
2390c99ee51aSKees Cook 	}
2391c99ee51aSKees Cook }
2392c99ee51aSKees Cook 
23932b7ea5b5STyler Hicks /*
23942b7ea5b5STyler Hicks  * Test detection of known and unknown filter flags. Userspace needs to be able
23952b7ea5b5STyler Hicks  * to check if a filter flag is supported by the current kernel and a good way
23962b7ea5b5STyler Hicks  * of doing that is by attempting to enter filter mode, with the flag bit in
23972b7ea5b5STyler Hicks  * question set, and a NULL pointer for the _args_ parameter. EFAULT indicates
23982b7ea5b5STyler Hicks  * that the flag is valid and EINVAL indicates that the flag is invalid.
23992b7ea5b5STyler Hicks  */
TEST(detect_seccomp_filter_flags)24002b7ea5b5STyler Hicks TEST(detect_seccomp_filter_flags)
24012b7ea5b5STyler Hicks {
2402e66a3997STyler Hicks 	unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC,
240300a02d0cSKees Cook 				 SECCOMP_FILTER_FLAG_LOG,
24046a21cc50STycho Andersen 				 SECCOMP_FILTER_FLAG_SPEC_ALLOW,
240551891498STycho Andersen 				 SECCOMP_FILTER_FLAG_NEW_LISTENER,
240651891498STycho Andersen 				 SECCOMP_FILTER_FLAG_TSYNC_ESRCH };
24074ee07767SKees Cook 	unsigned int exclusive[] = {
24084ee07767SKees Cook 				SECCOMP_FILTER_FLAG_TSYNC,
24094ee07767SKees Cook 				SECCOMP_FILTER_FLAG_NEW_LISTENER };
24104ee07767SKees Cook 	unsigned int flag, all_flags, exclusive_mask;
24112b7ea5b5STyler Hicks 	int i;
24122b7ea5b5STyler Hicks 	long ret;
24132b7ea5b5STyler Hicks 
24144ee07767SKees Cook 	/* Test detection of individual known-good filter flags */
24152b7ea5b5STyler Hicks 	for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) {
241600a02d0cSKees Cook 		int bits = 0;
241700a02d0cSKees Cook 
24182b7ea5b5STyler Hicks 		flag = flags[i];
241900a02d0cSKees Cook 		/* Make sure the flag is a single bit! */
242000a02d0cSKees Cook 		while (flag) {
242100a02d0cSKees Cook 			if (flag & 0x1)
242200a02d0cSKees Cook 				bits ++;
242300a02d0cSKees Cook 			flag >>= 1;
242400a02d0cSKees Cook 		}
242500a02d0cSKees Cook 		ASSERT_EQ(1, bits);
242600a02d0cSKees Cook 		flag = flags[i];
242700a02d0cSKees Cook 
24282b7ea5b5STyler Hicks 		ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
24292b7ea5b5STyler Hicks 		ASSERT_NE(ENOSYS, errno) {
24302b7ea5b5STyler Hicks 			TH_LOG("Kernel does not support seccomp syscall!");
24312b7ea5b5STyler Hicks 		}
24322b7ea5b5STyler Hicks 		EXPECT_EQ(-1, ret);
24332b7ea5b5STyler Hicks 		EXPECT_EQ(EFAULT, errno) {
24342b7ea5b5STyler Hicks 			TH_LOG("Failed to detect that a known-good filter flag (0x%X) is supported!",
24352b7ea5b5STyler Hicks 			       flag);
24362b7ea5b5STyler Hicks 		}
24372b7ea5b5STyler Hicks 
24382b7ea5b5STyler Hicks 		all_flags |= flag;
24392b7ea5b5STyler Hicks 	}
24402b7ea5b5STyler Hicks 
24414ee07767SKees Cook 	/*
24424ee07767SKees Cook 	 * Test detection of all known-good filter flags combined. But
24434ee07767SKees Cook 	 * for the exclusive flags we need to mask them out and try them
24444ee07767SKees Cook 	 * individually for the "all flags" testing.
24454ee07767SKees Cook 	 */
24464ee07767SKees Cook 	exclusive_mask = 0;
24474ee07767SKees Cook 	for (i = 0; i < ARRAY_SIZE(exclusive); i++)
24484ee07767SKees Cook 		exclusive_mask |= exclusive[i];
24494ee07767SKees Cook 	for (i = 0; i < ARRAY_SIZE(exclusive); i++) {
24504ee07767SKees Cook 		flag = all_flags & ~exclusive_mask;
24514ee07767SKees Cook 		flag |= exclusive[i];
24524ee07767SKees Cook 
24534ee07767SKees Cook 		ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
24542b7ea5b5STyler Hicks 		EXPECT_EQ(-1, ret);
24552b7ea5b5STyler Hicks 		EXPECT_EQ(EFAULT, errno) {
24562b7ea5b5STyler Hicks 			TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!",
24574ee07767SKees Cook 			       flag);
24584ee07767SKees Cook 		}
24592b7ea5b5STyler Hicks 	}
24602b7ea5b5STyler Hicks 
24614ee07767SKees Cook 	/* Test detection of an unknown filter flags, without exclusives. */
24622b7ea5b5STyler Hicks 	flag = -1;
24634ee07767SKees Cook 	flag &= ~exclusive_mask;
24642b7ea5b5STyler Hicks 	ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
24652b7ea5b5STyler Hicks 	EXPECT_EQ(-1, ret);
24662b7ea5b5STyler Hicks 	EXPECT_EQ(EINVAL, errno) {
24672b7ea5b5STyler Hicks 		TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported!",
24682b7ea5b5STyler Hicks 		       flag);
24692b7ea5b5STyler Hicks 	}
24702b7ea5b5STyler Hicks 
24712b7ea5b5STyler Hicks 	/*
24722b7ea5b5STyler Hicks 	 * Test detection of an unknown filter flag that may simply need to be
24732b7ea5b5STyler Hicks 	 * added to this test
24742b7ea5b5STyler Hicks 	 */
24752b7ea5b5STyler Hicks 	flag = flags[ARRAY_SIZE(flags) - 1] << 1;
24762b7ea5b5STyler Hicks 	ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
24772b7ea5b5STyler Hicks 	EXPECT_EQ(-1, ret);
24782b7ea5b5STyler Hicks 	EXPECT_EQ(EINVAL, errno) {
24792b7ea5b5STyler Hicks 		TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported! Does a new flag need to be added to this test?",
24802b7ea5b5STyler Hicks 		       flag);
24812b7ea5b5STyler Hicks 	}
24822b7ea5b5STyler Hicks }
24832b7ea5b5STyler Hicks 
TEST(TSYNC_first)2484c99ee51aSKees Cook TEST(TSYNC_first)
2485c99ee51aSKees Cook {
2486c99ee51aSKees Cook 	struct sock_filter filter[] = {
2487c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2488c99ee51aSKees Cook 	};
2489c99ee51aSKees Cook 	struct sock_fprog prog = {
2490c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
2491c99ee51aSKees Cook 		.filter = filter,
2492c99ee51aSKees Cook 	};
2493c99ee51aSKees Cook 	long ret;
2494c99ee51aSKees Cook 
2495c99ee51aSKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
2496c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2497c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2498c99ee51aSKees Cook 	}
2499c99ee51aSKees Cook 
25006c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2501c99ee51aSKees Cook 		      &prog);
2502b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2503b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2504b623c4daSKees Cook 	}
2505c99ee51aSKees Cook 	EXPECT_EQ(0, ret) {
2506c99ee51aSKees Cook 		TH_LOG("Could not install initial filter with TSYNC!");
2507c99ee51aSKees Cook 	}
2508c99ee51aSKees Cook }
2509c99ee51aSKees Cook 
2510c99ee51aSKees Cook #define TSYNC_SIBLINGS 2
2511c99ee51aSKees Cook struct tsync_sibling {
2512c99ee51aSKees Cook 	pthread_t tid;
2513c99ee51aSKees Cook 	pid_t system_tid;
2514c99ee51aSKees Cook 	sem_t *started;
2515c99ee51aSKees Cook 	pthread_cond_t *cond;
2516c99ee51aSKees Cook 	pthread_mutex_t *mutex;
2517c99ee51aSKees Cook 	int diverge;
2518c99ee51aSKees Cook 	int num_waits;
2519c99ee51aSKees Cook 	struct sock_fprog *prog;
2520c99ee51aSKees Cook 	struct __test_metadata *metadata;
2521c99ee51aSKees Cook };
2522c99ee51aSKees Cook 
252393bd70e3SKees Cook /*
252493bd70e3SKees Cook  * To avoid joining joined threads (which is not allowed by Bionic),
252593bd70e3SKees Cook  * make sure we both successfully join and clear the tid to skip a
252693bd70e3SKees Cook  * later join attempt during fixture teardown. Any remaining threads
252793bd70e3SKees Cook  * will be directly killed during teardown.
252893bd70e3SKees Cook  */
252993bd70e3SKees Cook #define PTHREAD_JOIN(tid, status)					\
253093bd70e3SKees Cook 	do {								\
253193bd70e3SKees Cook 		int _rc = pthread_join(tid, status);			\
253293bd70e3SKees Cook 		if (_rc) {						\
253393bd70e3SKees Cook 			TH_LOG("pthread_join of tid %u failed: %d\n",	\
253493bd70e3SKees Cook 				(unsigned int)tid, _rc);		\
253593bd70e3SKees Cook 		} else {						\
253693bd70e3SKees Cook 			tid = 0;					\
253793bd70e3SKees Cook 		}							\
253893bd70e3SKees Cook 	} while (0)
253993bd70e3SKees Cook 
FIXTURE(TSYNC)25401ae81d78SKees Cook FIXTURE(TSYNC) {
2541c99ee51aSKees Cook 	struct sock_fprog root_prog, apply_prog;
2542c99ee51aSKees Cook 	struct tsync_sibling sibling[TSYNC_SIBLINGS];
2543c99ee51aSKees Cook 	sem_t started;
2544c99ee51aSKees Cook 	pthread_cond_t cond;
2545c99ee51aSKees Cook 	pthread_mutex_t mutex;
2546c99ee51aSKees Cook 	int sibling_count;
2547c99ee51aSKees Cook };
2548c99ee51aSKees Cook 
FIXTURE_SETUP(TSYNC)2549c99ee51aSKees Cook FIXTURE_SETUP(TSYNC)
2550c99ee51aSKees Cook {
2551c99ee51aSKees Cook 	struct sock_filter root_filter[] = {
2552c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2553c99ee51aSKees Cook 	};
2554c99ee51aSKees Cook 	struct sock_filter apply_filter[] = {
2555c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
2556c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
2557c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),
2558c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
2559c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2560c99ee51aSKees Cook 	};
2561c99ee51aSKees Cook 
2562c99ee51aSKees Cook 	memset(&self->root_prog, 0, sizeof(self->root_prog));
2563c99ee51aSKees Cook 	memset(&self->apply_prog, 0, sizeof(self->apply_prog));
2564c99ee51aSKees Cook 	memset(&self->sibling, 0, sizeof(self->sibling));
2565c99ee51aSKees Cook 	self->root_prog.filter = malloc(sizeof(root_filter));
2566c99ee51aSKees Cook 	ASSERT_NE(NULL, self->root_prog.filter);
2567c99ee51aSKees Cook 	memcpy(self->root_prog.filter, &root_filter, sizeof(root_filter));
2568c99ee51aSKees Cook 	self->root_prog.len = (unsigned short)ARRAY_SIZE(root_filter);
2569c99ee51aSKees Cook 
2570c99ee51aSKees Cook 	self->apply_prog.filter = malloc(sizeof(apply_filter));
2571c99ee51aSKees Cook 	ASSERT_NE(NULL, self->apply_prog.filter);
2572c99ee51aSKees Cook 	memcpy(self->apply_prog.filter, &apply_filter, sizeof(apply_filter));
2573c99ee51aSKees Cook 	self->apply_prog.len = (unsigned short)ARRAY_SIZE(apply_filter);
2574c99ee51aSKees Cook 
2575c99ee51aSKees Cook 	self->sibling_count = 0;
2576c99ee51aSKees Cook 	pthread_mutex_init(&self->mutex, NULL);
2577c99ee51aSKees Cook 	pthread_cond_init(&self->cond, NULL);
2578c99ee51aSKees Cook 	sem_init(&self->started, 0, 0);
2579c99ee51aSKees Cook 	self->sibling[0].tid = 0;
2580c99ee51aSKees Cook 	self->sibling[0].cond = &self->cond;
2581c99ee51aSKees Cook 	self->sibling[0].started = &self->started;
2582c99ee51aSKees Cook 	self->sibling[0].mutex = &self->mutex;
2583c99ee51aSKees Cook 	self->sibling[0].diverge = 0;
2584c99ee51aSKees Cook 	self->sibling[0].num_waits = 1;
2585c99ee51aSKees Cook 	self->sibling[0].prog = &self->root_prog;
2586c99ee51aSKees Cook 	self->sibling[0].metadata = _metadata;
2587c99ee51aSKees Cook 	self->sibling[1].tid = 0;
2588c99ee51aSKees Cook 	self->sibling[1].cond = &self->cond;
2589c99ee51aSKees Cook 	self->sibling[1].started = &self->started;
2590c99ee51aSKees Cook 	self->sibling[1].mutex = &self->mutex;
2591c99ee51aSKees Cook 	self->sibling[1].diverge = 0;
2592c99ee51aSKees Cook 	self->sibling[1].prog = &self->root_prog;
2593c99ee51aSKees Cook 	self->sibling[1].num_waits = 1;
2594c99ee51aSKees Cook 	self->sibling[1].metadata = _metadata;
2595c99ee51aSKees Cook }
2596c99ee51aSKees Cook 
FIXTURE_TEARDOWN(TSYNC)2597c99ee51aSKees Cook FIXTURE_TEARDOWN(TSYNC)
2598c99ee51aSKees Cook {
2599c99ee51aSKees Cook 	int sib = 0;
2600c99ee51aSKees Cook 
2601c99ee51aSKees Cook 	if (self->root_prog.filter)
2602c99ee51aSKees Cook 		free(self->root_prog.filter);
2603c99ee51aSKees Cook 	if (self->apply_prog.filter)
2604c99ee51aSKees Cook 		free(self->apply_prog.filter);
2605c99ee51aSKees Cook 
2606c99ee51aSKees Cook 	for ( ; sib < self->sibling_count; ++sib) {
2607c99ee51aSKees Cook 		struct tsync_sibling *s = &self->sibling[sib];
2608c99ee51aSKees Cook 
2609c99ee51aSKees Cook 		if (!s->tid)
2610c99ee51aSKees Cook 			continue;
261193bd70e3SKees Cook 		/*
261293bd70e3SKees Cook 		 * If a thread is still running, it may be stuck, so hit
261393bd70e3SKees Cook 		 * it over the head really hard.
261493bd70e3SKees Cook 		 */
261593bd70e3SKees Cook 		pthread_kill(s->tid, 9);
2616c99ee51aSKees Cook 	}
2617c99ee51aSKees Cook 	pthread_mutex_destroy(&self->mutex);
2618c99ee51aSKees Cook 	pthread_cond_destroy(&self->cond);
2619c99ee51aSKees Cook 	sem_destroy(&self->started);
2620c99ee51aSKees Cook }
2621c99ee51aSKees Cook 
tsync_sibling(void * data)2622c99ee51aSKees Cook void *tsync_sibling(void *data)
2623c99ee51aSKees Cook {
2624c99ee51aSKees Cook 	long ret = 0;
2625c99ee51aSKees Cook 	struct tsync_sibling *me = data;
2626c99ee51aSKees Cook 
2627c99ee51aSKees Cook 	me->system_tid = syscall(__NR_gettid);
2628c99ee51aSKees Cook 
2629c99ee51aSKees Cook 	pthread_mutex_lock(me->mutex);
2630c99ee51aSKees Cook 	if (me->diverge) {
2631c99ee51aSKees Cook 		/* Just re-apply the root prog to fork the tree */
2632c99ee51aSKees Cook 		ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,
2633c99ee51aSKees Cook 				me->prog, 0, 0);
2634c99ee51aSKees Cook 	}
2635c99ee51aSKees Cook 	sem_post(me->started);
2636c99ee51aSKees Cook 	/* Return outside of started so parent notices failures. */
2637c99ee51aSKees Cook 	if (ret) {
2638c99ee51aSKees Cook 		pthread_mutex_unlock(me->mutex);
2639c99ee51aSKees Cook 		return (void *)SIBLING_EXIT_FAILURE;
2640c99ee51aSKees Cook 	}
2641c99ee51aSKees Cook 	do {
2642c99ee51aSKees Cook 		pthread_cond_wait(me->cond, me->mutex);
2643c99ee51aSKees Cook 		me->num_waits = me->num_waits - 1;
2644c99ee51aSKees Cook 	} while (me->num_waits);
2645c99ee51aSKees Cook 	pthread_mutex_unlock(me->mutex);
2646c99ee51aSKees Cook 
2647c99ee51aSKees Cook 	ret = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
2648c99ee51aSKees Cook 	if (!ret)
2649c99ee51aSKees Cook 		return (void *)SIBLING_EXIT_NEWPRIVS;
26502bfed7d2SJann Horn 	read(-1, NULL, 0);
2651c99ee51aSKees Cook 	return (void *)SIBLING_EXIT_UNKILLED;
2652c99ee51aSKees Cook }
2653c99ee51aSKees Cook 
tsync_start_sibling(struct tsync_sibling * sibling)2654c99ee51aSKees Cook void tsync_start_sibling(struct tsync_sibling *sibling)
2655c99ee51aSKees Cook {
2656c99ee51aSKees Cook 	pthread_create(&sibling->tid, NULL, tsync_sibling, (void *)sibling);
2657c99ee51aSKees Cook }
2658c99ee51aSKees Cook 
TEST_F(TSYNC,siblings_fail_prctl)2659c99ee51aSKees Cook TEST_F(TSYNC, siblings_fail_prctl)
2660c99ee51aSKees Cook {
2661c99ee51aSKees Cook 	long ret;
2662c99ee51aSKees Cook 	void *status;
2663c99ee51aSKees Cook 	struct sock_filter filter[] = {
2664c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
2665c99ee51aSKees Cook 			offsetof(struct seccomp_data, nr)),
2666c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1),
2667c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | EINVAL),
2668c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
2669c99ee51aSKees Cook 	};
2670c99ee51aSKees Cook 	struct sock_fprog prog = {
2671c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
2672c99ee51aSKees Cook 		.filter = filter,
2673c99ee51aSKees Cook 	};
2674c99ee51aSKees Cook 
2675c99ee51aSKees Cook 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
2676c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2677c99ee51aSKees Cook 	}
2678c99ee51aSKees Cook 
2679c99ee51aSKees Cook 	/* Check prctl failure detection by requesting sib 0 diverge. */
2680c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
2681b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2682b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2683b623c4daSKees Cook 	}
2684c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2685c99ee51aSKees Cook 		TH_LOG("setting filter failed");
2686c99ee51aSKees Cook 	}
2687c99ee51aSKees Cook 
2688c99ee51aSKees Cook 	self->sibling[0].diverge = 1;
2689c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[0]);
2690c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[1]);
2691c99ee51aSKees Cook 
2692c99ee51aSKees Cook 	while (self->sibling_count < TSYNC_SIBLINGS) {
2693c99ee51aSKees Cook 		sem_wait(&self->started);
2694c99ee51aSKees Cook 		self->sibling_count++;
2695c99ee51aSKees Cook 	}
2696c99ee51aSKees Cook 
2697c99ee51aSKees Cook 	/* Signal the threads to clean up*/
2698c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2699c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2700c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2701c99ee51aSKees Cook 	}
2702c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
2703c99ee51aSKees Cook 
2704c99ee51aSKees Cook 	/* Ensure diverging sibling failed to call prctl. */
270593bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[0].tid, &status);
2706c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_FAILURE, (long)status);
270793bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[1].tid, &status);
2708c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
2709c99ee51aSKees Cook }
2710c99ee51aSKees Cook 
TEST_F(TSYNC,two_siblings_with_ancestor)2711c99ee51aSKees Cook TEST_F(TSYNC, two_siblings_with_ancestor)
2712c99ee51aSKees Cook {
2713c99ee51aSKees Cook 	long ret;
2714c99ee51aSKees Cook 	void *status;
2715c99ee51aSKees Cook 
2716c99ee51aSKees Cook 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
2717c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2718c99ee51aSKees Cook 	}
2719c99ee51aSKees Cook 
2720c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
2721b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2722b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2723b623c4daSKees Cook 	}
2724c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2725c99ee51aSKees Cook 		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
2726c99ee51aSKees Cook 	}
2727c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[0]);
2728c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[1]);
2729c99ee51aSKees Cook 
2730c99ee51aSKees Cook 	while (self->sibling_count < TSYNC_SIBLINGS) {
2731c99ee51aSKees Cook 		sem_wait(&self->started);
2732c99ee51aSKees Cook 		self->sibling_count++;
2733c99ee51aSKees Cook 	}
2734c99ee51aSKees Cook 
27356c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2736c99ee51aSKees Cook 		      &self->apply_prog);
2737c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2738c99ee51aSKees Cook 		TH_LOG("Could install filter on all threads!");
2739c99ee51aSKees Cook 	}
2740c99ee51aSKees Cook 	/* Tell the siblings to test the policy */
2741c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2742c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2743c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2744c99ee51aSKees Cook 	}
2745c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
2746c99ee51aSKees Cook 	/* Ensure they are both killed and don't exit cleanly. */
274793bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[0].tid, &status);
2748c99ee51aSKees Cook 	EXPECT_EQ(0x0, (long)status);
274993bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[1].tid, &status);
2750c99ee51aSKees Cook 	EXPECT_EQ(0x0, (long)status);
2751c99ee51aSKees Cook }
2752c99ee51aSKees Cook 
TEST_F(TSYNC,two_sibling_want_nnp)2753c99ee51aSKees Cook TEST_F(TSYNC, two_sibling_want_nnp)
2754c99ee51aSKees Cook {
2755c99ee51aSKees Cook 	void *status;
2756c99ee51aSKees Cook 
2757c99ee51aSKees Cook 	/* start siblings before any prctl() operations */
2758c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[0]);
2759c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[1]);
2760c99ee51aSKees Cook 	while (self->sibling_count < TSYNC_SIBLINGS) {
2761c99ee51aSKees Cook 		sem_wait(&self->started);
2762c99ee51aSKees Cook 		self->sibling_count++;
2763c99ee51aSKees Cook 	}
2764c99ee51aSKees Cook 
2765c99ee51aSKees Cook 	/* Tell the siblings to test no policy */
2766c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2767c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2768c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2769c99ee51aSKees Cook 	}
2770c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
2771c99ee51aSKees Cook 
2772c99ee51aSKees Cook 	/* Ensure they are both upset about lacking nnp. */
277393bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[0].tid, &status);
2774c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status);
277593bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[1].tid, &status);
2776c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status);
2777c99ee51aSKees Cook }
2778c99ee51aSKees Cook 
TEST_F(TSYNC,two_siblings_with_no_filter)2779c99ee51aSKees Cook TEST_F(TSYNC, two_siblings_with_no_filter)
2780c99ee51aSKees Cook {
2781c99ee51aSKees Cook 	long ret;
2782c99ee51aSKees Cook 	void *status;
2783c99ee51aSKees Cook 
2784c99ee51aSKees Cook 	/* start siblings before any prctl() operations */
2785c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[0]);
2786c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[1]);
2787c99ee51aSKees Cook 	while (self->sibling_count < TSYNC_SIBLINGS) {
2788c99ee51aSKees Cook 		sem_wait(&self->started);
2789c99ee51aSKees Cook 		self->sibling_count++;
2790c99ee51aSKees Cook 	}
2791c99ee51aSKees Cook 
2792c99ee51aSKees Cook 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
2793c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2794c99ee51aSKees Cook 	}
2795c99ee51aSKees Cook 
27966c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2797c99ee51aSKees Cook 		      &self->apply_prog);
2798b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2799b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2800b623c4daSKees Cook 	}
2801c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2802c99ee51aSKees Cook 		TH_LOG("Could install filter on all threads!");
2803c99ee51aSKees Cook 	}
2804c99ee51aSKees Cook 
2805c99ee51aSKees Cook 	/* Tell the siblings to test the policy */
2806c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2807c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2808c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2809c99ee51aSKees Cook 	}
2810c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
2811c99ee51aSKees Cook 
2812c99ee51aSKees Cook 	/* Ensure they are both killed and don't exit cleanly. */
281393bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[0].tid, &status);
2814c99ee51aSKees Cook 	EXPECT_EQ(0x0, (long)status);
281593bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[1].tid, &status);
2816c99ee51aSKees Cook 	EXPECT_EQ(0x0, (long)status);
2817c99ee51aSKees Cook }
2818c99ee51aSKees Cook 
TEST_F(TSYNC,two_siblings_with_one_divergence)2819c99ee51aSKees Cook TEST_F(TSYNC, two_siblings_with_one_divergence)
2820c99ee51aSKees Cook {
2821c99ee51aSKees Cook 	long ret;
2822c99ee51aSKees Cook 	void *status;
2823c99ee51aSKees Cook 
2824c99ee51aSKees Cook 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
2825c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2826c99ee51aSKees Cook 	}
2827c99ee51aSKees Cook 
2828c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
2829b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2830b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2831b623c4daSKees Cook 	}
2832c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2833c99ee51aSKees Cook 		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
2834c99ee51aSKees Cook 	}
2835c99ee51aSKees Cook 	self->sibling[0].diverge = 1;
2836c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[0]);
2837c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[1]);
2838c99ee51aSKees Cook 
2839c99ee51aSKees Cook 	while (self->sibling_count < TSYNC_SIBLINGS) {
2840c99ee51aSKees Cook 		sem_wait(&self->started);
2841c99ee51aSKees Cook 		self->sibling_count++;
2842c99ee51aSKees Cook 	}
2843c99ee51aSKees Cook 
28446c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2845c99ee51aSKees Cook 		      &self->apply_prog);
2846c99ee51aSKees Cook 	ASSERT_EQ(self->sibling[0].system_tid, ret) {
2847c99ee51aSKees Cook 		TH_LOG("Did not fail on diverged sibling.");
2848c99ee51aSKees Cook 	}
2849c99ee51aSKees Cook 
2850c99ee51aSKees Cook 	/* Wake the threads */
2851c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2852c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2853c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2854c99ee51aSKees Cook 	}
2855c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
2856c99ee51aSKees Cook 
2857c99ee51aSKees Cook 	/* Ensure they are both unkilled. */
285893bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[0].tid, &status);
2859c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
286093bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[1].tid, &status);
2861c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
2862c99ee51aSKees Cook }
2863c99ee51aSKees Cook 
TEST_F(TSYNC,two_siblings_with_one_divergence_no_tid_in_err)286451891498STycho Andersen TEST_F(TSYNC, two_siblings_with_one_divergence_no_tid_in_err)
286551891498STycho Andersen {
286651891498STycho Andersen 	long ret, flags;
286751891498STycho Andersen 	void *status;
286851891498STycho Andersen 
286951891498STycho Andersen 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
287051891498STycho Andersen 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
287151891498STycho Andersen 	}
287251891498STycho Andersen 
287351891498STycho Andersen 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
287451891498STycho Andersen 	ASSERT_NE(ENOSYS, errno) {
287551891498STycho Andersen 		TH_LOG("Kernel does not support seccomp syscall!");
287651891498STycho Andersen 	}
287751891498STycho Andersen 	ASSERT_EQ(0, ret) {
287851891498STycho Andersen 		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
287951891498STycho Andersen 	}
288051891498STycho Andersen 	self->sibling[0].diverge = 1;
288151891498STycho Andersen 	tsync_start_sibling(&self->sibling[0]);
288251891498STycho Andersen 	tsync_start_sibling(&self->sibling[1]);
288351891498STycho Andersen 
288451891498STycho Andersen 	while (self->sibling_count < TSYNC_SIBLINGS) {
288551891498STycho Andersen 		sem_wait(&self->started);
288651891498STycho Andersen 		self->sibling_count++;
288751891498STycho Andersen 	}
288851891498STycho Andersen 
288951891498STycho Andersen 	flags = SECCOMP_FILTER_FLAG_TSYNC | \
289051891498STycho Andersen 		SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
289151891498STycho Andersen 	ret = seccomp(SECCOMP_SET_MODE_FILTER, flags, &self->apply_prog);
289251891498STycho Andersen 	ASSERT_EQ(ESRCH, errno) {
289351891498STycho Andersen 		TH_LOG("Did not return ESRCH for diverged sibling.");
289451891498STycho Andersen 	}
289551891498STycho Andersen 	ASSERT_EQ(-1, ret) {
289651891498STycho Andersen 		TH_LOG("Did not fail on diverged sibling.");
289751891498STycho Andersen 	}
289851891498STycho Andersen 
289951891498STycho Andersen 	/* Wake the threads */
290051891498STycho Andersen 	pthread_mutex_lock(&self->mutex);
290151891498STycho Andersen 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
290251891498STycho Andersen 		TH_LOG("cond broadcast non-zero");
290351891498STycho Andersen 	}
290451891498STycho Andersen 	pthread_mutex_unlock(&self->mutex);
290551891498STycho Andersen 
290651891498STycho Andersen 	/* Ensure they are both unkilled. */
290751891498STycho Andersen 	PTHREAD_JOIN(self->sibling[0].tid, &status);
290851891498STycho Andersen 	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
290951891498STycho Andersen 	PTHREAD_JOIN(self->sibling[1].tid, &status);
291051891498STycho Andersen 	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
291151891498STycho Andersen }
291251891498STycho Andersen 
TEST_F(TSYNC,two_siblings_not_under_filter)2913c99ee51aSKees Cook TEST_F(TSYNC, two_siblings_not_under_filter)
2914c99ee51aSKees Cook {
2915c99ee51aSKees Cook 	long ret, sib;
2916c99ee51aSKees Cook 	void *status;
2917ed492c2aSKees Cook 	struct timespec delay = { .tv_nsec = 100000000 };
2918c99ee51aSKees Cook 
2919c99ee51aSKees Cook 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
2920c99ee51aSKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
2921c99ee51aSKees Cook 	}
2922c99ee51aSKees Cook 
2923c99ee51aSKees Cook 	/*
2924c99ee51aSKees Cook 	 * Sibling 0 will have its own seccomp policy
2925c99ee51aSKees Cook 	 * and Sibling 1 will not be under seccomp at
2926c99ee51aSKees Cook 	 * all. Sibling 1 will enter seccomp and 0
2927c99ee51aSKees Cook 	 * will cause failure.
2928c99ee51aSKees Cook 	 */
2929c99ee51aSKees Cook 	self->sibling[0].diverge = 1;
2930c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[0]);
2931c99ee51aSKees Cook 	tsync_start_sibling(&self->sibling[1]);
2932c99ee51aSKees Cook 
2933c99ee51aSKees Cook 	while (self->sibling_count < TSYNC_SIBLINGS) {
2934c99ee51aSKees Cook 		sem_wait(&self->started);
2935c99ee51aSKees Cook 		self->sibling_count++;
2936c99ee51aSKees Cook 	}
2937c99ee51aSKees Cook 
2938c99ee51aSKees Cook 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
2939b623c4daSKees Cook 	ASSERT_NE(ENOSYS, errno) {
2940b623c4daSKees Cook 		TH_LOG("Kernel does not support seccomp syscall!");
2941b623c4daSKees Cook 	}
2942c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2943c99ee51aSKees Cook 		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
2944c99ee51aSKees Cook 	}
2945c99ee51aSKees Cook 
29466c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2947c99ee51aSKees Cook 		      &self->apply_prog);
2948c99ee51aSKees Cook 	ASSERT_EQ(ret, self->sibling[0].system_tid) {
2949c99ee51aSKees Cook 		TH_LOG("Did not fail on diverged sibling.");
2950c99ee51aSKees Cook 	}
2951c99ee51aSKees Cook 	sib = 1;
2952c99ee51aSKees Cook 	if (ret == self->sibling[0].system_tid)
2953c99ee51aSKees Cook 		sib = 0;
2954c99ee51aSKees Cook 
2955c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2956c99ee51aSKees Cook 
2957c99ee51aSKees Cook 	/* Increment the other siblings num_waits so we can clean up
2958c99ee51aSKees Cook 	 * the one we just saw.
2959c99ee51aSKees Cook 	 */
2960c99ee51aSKees Cook 	self->sibling[!sib].num_waits += 1;
2961c99ee51aSKees Cook 
2962c99ee51aSKees Cook 	/* Signal the thread to clean up*/
2963c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2964c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2965c99ee51aSKees Cook 	}
2966c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
296793bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[sib].tid, &status);
2968c99ee51aSKees Cook 	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
2969c99ee51aSKees Cook 	/* Poll for actual task death. pthread_join doesn't guarantee it. */
2970c99ee51aSKees Cook 	while (!kill(self->sibling[sib].system_tid, 0))
2971ed492c2aSKees Cook 		nanosleep(&delay, NULL);
2972c99ee51aSKees Cook 	/* Switch to the remaining sibling */
2973c99ee51aSKees Cook 	sib = !sib;
2974c99ee51aSKees Cook 
29756c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2976c99ee51aSKees Cook 		      &self->apply_prog);
2977c99ee51aSKees Cook 	ASSERT_EQ(0, ret) {
2978c99ee51aSKees Cook 		TH_LOG("Expected the remaining sibling to sync");
2979c99ee51aSKees Cook 	};
2980c99ee51aSKees Cook 
2981c99ee51aSKees Cook 	pthread_mutex_lock(&self->mutex);
2982c99ee51aSKees Cook 
2983c99ee51aSKees Cook 	/* If remaining sibling didn't have a chance to wake up during
2984c99ee51aSKees Cook 	 * the first broadcast, manually reduce the num_waits now.
2985c99ee51aSKees Cook 	 */
2986c99ee51aSKees Cook 	if (self->sibling[sib].num_waits > 1)
2987c99ee51aSKees Cook 		self->sibling[sib].num_waits = 1;
2988c99ee51aSKees Cook 	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
2989c99ee51aSKees Cook 		TH_LOG("cond broadcast non-zero");
2990c99ee51aSKees Cook 	}
2991c99ee51aSKees Cook 	pthread_mutex_unlock(&self->mutex);
299293bd70e3SKees Cook 	PTHREAD_JOIN(self->sibling[sib].tid, &status);
2993c99ee51aSKees Cook 	EXPECT_EQ(0, (long)status);
2994c99ee51aSKees Cook 	/* Poll for actual task death. pthread_join doesn't guarantee it. */
2995c99ee51aSKees Cook 	while (!kill(self->sibling[sib].system_tid, 0))
2996ed492c2aSKees Cook 		nanosleep(&delay, NULL);
2997c99ee51aSKees Cook 
29986c045d07SMickaël Salaün 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
2999c99ee51aSKees Cook 		      &self->apply_prog);
3000c99ee51aSKees Cook 	ASSERT_EQ(0, ret);  /* just us chickens */
3001c99ee51aSKees Cook }
3002c99ee51aSKees Cook 
3003c99ee51aSKees Cook /* Make sure restarted syscalls are seen directly as "restart_syscall". */
TEST(syscall_restart)3004c99ee51aSKees Cook TEST(syscall_restart)
3005c99ee51aSKees Cook {
3006c99ee51aSKees Cook 	long ret;
3007c99ee51aSKees Cook 	unsigned long msg;
3008c99ee51aSKees Cook 	pid_t child_pid;
3009c99ee51aSKees Cook 	int pipefd[2];
3010c99ee51aSKees Cook 	int status;
3011c99ee51aSKees Cook 	siginfo_t info = { };
3012c99ee51aSKees Cook 	struct sock_filter filter[] = {
3013c99ee51aSKees Cook 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
3014c99ee51aSKees Cook 			 offsetof(struct seccomp_data, nr)),
3015c99ee51aSKees Cook 
3016c99ee51aSKees Cook #ifdef __NR_sigreturn
3017d42b8dbeSThadeu Lima de Souza Cascardo 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_sigreturn, 7, 0),
3018c99ee51aSKees Cook #endif
3019d42b8dbeSThadeu Lima de Souza Cascardo 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 6, 0),
3020d42b8dbeSThadeu Lima de Souza Cascardo 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit, 5, 0),
3021d42b8dbeSThadeu Lima de Souza Cascardo 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_rt_sigreturn, 4, 0),
3022d42b8dbeSThadeu Lima de Souza Cascardo 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_nanosleep, 5, 0),
3023d42b8dbeSThadeu Lima de Souza Cascardo 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_clock_nanosleep, 4, 0),
3024c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_restart_syscall, 4, 0),
3025c99ee51aSKees Cook 
3026c99ee51aSKees Cook 		/* Allow __NR_write for easy logging. */
3027c99ee51aSKees Cook 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_write, 0, 1),
3028c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
3029c99ee51aSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
3030256d0afbSKees Cook 		/* The nanosleep jump target. */
3031256d0afbSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100),
3032256d0afbSKees Cook 		/* The restart_syscall jump target. */
3033256d0afbSKees Cook 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200),
3034c99ee51aSKees Cook 	};
3035c99ee51aSKees Cook 	struct sock_fprog prog = {
3036c99ee51aSKees Cook 		.len = (unsigned short)ARRAY_SIZE(filter),
3037c99ee51aSKees Cook 		.filter = filter,
3038c99ee51aSKees Cook 	};
3039256d0afbSKees Cook #if defined(__arm__)
3040256d0afbSKees Cook 	struct utsname utsbuf;
3041256d0afbSKees Cook #endif
3042c99ee51aSKees Cook 
3043c99ee51aSKees Cook 	ASSERT_EQ(0, pipe(pipefd));
3044c99ee51aSKees Cook 
3045c99ee51aSKees Cook 	child_pid = fork();
3046c99ee51aSKees Cook 	ASSERT_LE(0, child_pid);
3047c99ee51aSKees Cook 	if (child_pid == 0) {
3048c99ee51aSKees Cook 		/* Child uses EXPECT not ASSERT to deliver status correctly. */
3049c99ee51aSKees Cook 		char buf = ' ';
3050256d0afbSKees Cook 		struct timespec timeout = { };
3051c99ee51aSKees Cook 
3052c99ee51aSKees Cook 		/* Attach parent as tracer and stop. */
3053c99ee51aSKees Cook 		EXPECT_EQ(0, ptrace(PTRACE_TRACEME));
3054c99ee51aSKees Cook 		EXPECT_EQ(0, raise(SIGSTOP));
3055c99ee51aSKees Cook 
3056c99ee51aSKees Cook 		EXPECT_EQ(0, close(pipefd[1]));
3057c99ee51aSKees Cook 
3058c99ee51aSKees Cook 		EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
3059c99ee51aSKees Cook 			TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3060c99ee51aSKees Cook 		}
3061c99ee51aSKees Cook 
3062c99ee51aSKees Cook 		ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
3063c99ee51aSKees Cook 		EXPECT_EQ(0, ret) {
3064c99ee51aSKees Cook 			TH_LOG("Failed to install filter!");
3065c99ee51aSKees Cook 		}
3066c99ee51aSKees Cook 
3067c99ee51aSKees Cook 		EXPECT_EQ(1, read(pipefd[0], &buf, 1)) {
3068c99ee51aSKees Cook 			TH_LOG("Failed to read() sync from parent");
3069c99ee51aSKees Cook 		}
3070c99ee51aSKees Cook 		EXPECT_EQ('.', buf) {
3071c99ee51aSKees Cook 			TH_LOG("Failed to get sync data from read()");
3072c99ee51aSKees Cook 		}
3073c99ee51aSKees Cook 
3074256d0afbSKees Cook 		/* Start nanosleep to be interrupted. */
3075256d0afbSKees Cook 		timeout.tv_sec = 1;
3076c99ee51aSKees Cook 		errno = 0;
3077256d0afbSKees Cook 		EXPECT_EQ(0, nanosleep(&timeout, NULL)) {
3078fbc5d382SKees Cook 			TH_LOG("Call to nanosleep() failed (errno %d: %s)",
3079fbc5d382SKees Cook 				errno, strerror(errno));
3080c99ee51aSKees Cook 		}
3081c99ee51aSKees Cook 
3082c99ee51aSKees Cook 		/* Read final sync from parent. */
3083c99ee51aSKees Cook 		EXPECT_EQ(1, read(pipefd[0], &buf, 1)) {
3084c99ee51aSKees Cook 			TH_LOG("Failed final read() from parent");
3085c99ee51aSKees Cook 		}
3086c99ee51aSKees Cook 		EXPECT_EQ('!', buf) {
3087c99ee51aSKees Cook 			TH_LOG("Failed to get final data from read()");
3088c99ee51aSKees Cook 		}
3089c99ee51aSKees Cook 
3090c99ee51aSKees Cook 		/* Directly report the status of our test harness results. */
3091c99ee51aSKees Cook 		syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS
3092c99ee51aSKees Cook 						     : EXIT_FAILURE);
3093c99ee51aSKees Cook 	}
3094c99ee51aSKees Cook 	EXPECT_EQ(0, close(pipefd[0]));
3095c99ee51aSKees Cook 
3096c99ee51aSKees Cook 	/* Attach to child, setup options, and release. */
3097c99ee51aSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
3098c99ee51aSKees Cook 	ASSERT_EQ(true, WIFSTOPPED(status));
3099c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_SETOPTIONS, child_pid, NULL,
3100c99ee51aSKees Cook 			    PTRACE_O_TRACESECCOMP));
3101c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
3102c99ee51aSKees Cook 	ASSERT_EQ(1, write(pipefd[1], ".", 1));
3103c99ee51aSKees Cook 
3104256d0afbSKees Cook 	/* Wait for nanosleep() to start. */
3105c99ee51aSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
3106c99ee51aSKees Cook 	ASSERT_EQ(true, WIFSTOPPED(status));
3107c99ee51aSKees Cook 	ASSERT_EQ(SIGTRAP, WSTOPSIG(status));
3108c99ee51aSKees Cook 	ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16));
3109c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg));
3110c99ee51aSKees Cook 	ASSERT_EQ(0x100, msg);
3111d42b8dbeSThadeu Lima de Souza Cascardo 	ret = get_syscall(_metadata, child_pid);
3112d42b8dbeSThadeu Lima de Souza Cascardo 	EXPECT_TRUE(ret == __NR_nanosleep || ret == __NR_clock_nanosleep);
3113c99ee51aSKees Cook 
3114c99ee51aSKees Cook 	/* Might as well check siginfo for sanity while we're here. */
3115c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
3116c99ee51aSKees Cook 	ASSERT_EQ(SIGTRAP, info.si_signo);
3117c99ee51aSKees Cook 	ASSERT_EQ(SIGTRAP | (PTRACE_EVENT_SECCOMP << 8), info.si_code);
3118c99ee51aSKees Cook 	EXPECT_EQ(0, info.si_errno);
3119c99ee51aSKees Cook 	EXPECT_EQ(getuid(), info.si_uid);
3120c99ee51aSKees Cook 	/* Verify signal delivery came from child (seccomp-triggered). */
3121c99ee51aSKees Cook 	EXPECT_EQ(child_pid, info.si_pid);
3122c99ee51aSKees Cook 
3123256d0afbSKees Cook 	/* Interrupt nanosleep with SIGSTOP (which we'll need to handle). */
3124c99ee51aSKees Cook 	ASSERT_EQ(0, kill(child_pid, SIGSTOP));
3125c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
3126c99ee51aSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
3127c99ee51aSKees Cook 	ASSERT_EQ(true, WIFSTOPPED(status));
3128c99ee51aSKees Cook 	ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
3129c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
31302bd61abeSKees Cook 	/*
31312bd61abeSKees Cook 	 * There is no siginfo on SIGSTOP any more, so we can't verify
31322bd61abeSKees Cook 	 * signal delivery came from parent now (getpid() == info.si_pid).
31332bd61abeSKees Cook 	 * https://lkml.kernel.org/r/CAGXu5jJaZAOzP1qFz66tYrtbuywqb+UN2SOA1VLHpCCOiYvYeg@mail.gmail.com
31342bd61abeSKees Cook 	 * At least verify the SIGSTOP via PTRACE_GETSIGINFO.
31352bd61abeSKees Cook 	 */
31362bd61abeSKees Cook 	EXPECT_EQ(SIGSTOP, info.si_signo);
3137c99ee51aSKees Cook 
3138256d0afbSKees Cook 	/* Restart nanosleep with SIGCONT, which triggers restart_syscall. */
3139c99ee51aSKees Cook 	ASSERT_EQ(0, kill(child_pid, SIGCONT));
3140c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
3141c99ee51aSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
3142c99ee51aSKees Cook 	ASSERT_EQ(true, WIFSTOPPED(status));
3143c99ee51aSKees Cook 	ASSERT_EQ(SIGCONT, WSTOPSIG(status));
3144c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
3145c99ee51aSKees Cook 
3146c99ee51aSKees Cook 	/* Wait for restart_syscall() to start. */
3147c99ee51aSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
3148c99ee51aSKees Cook 	ASSERT_EQ(true, WIFSTOPPED(status));
3149c99ee51aSKees Cook 	ASSERT_EQ(SIGTRAP, WSTOPSIG(status));
3150c99ee51aSKees Cook 	ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16));
3151c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg));
3152256d0afbSKees Cook 
3153c99ee51aSKees Cook 	ASSERT_EQ(0x200, msg);
3154c99ee51aSKees Cook 	ret = get_syscall(_metadata, child_pid);
3155c99ee51aSKees Cook #if defined(__arm__)
3156256d0afbSKees Cook 	/*
3157256d0afbSKees Cook 	 * FIXME:
3158256d0afbSKees Cook 	 * - native ARM registers do NOT expose true syscall.
3159256d0afbSKees Cook 	 * - compat ARM registers on ARM64 DO expose true syscall.
3160256d0afbSKees Cook 	 */
3161256d0afbSKees Cook 	ASSERT_EQ(0, uname(&utsbuf));
3162256d0afbSKees Cook 	if (strncmp(utsbuf.machine, "arm", 3) == 0) {
3163256d0afbSKees Cook 		EXPECT_EQ(__NR_nanosleep, ret);
3164256d0afbSKees Cook 	} else
3165c99ee51aSKees Cook #endif
3166256d0afbSKees Cook 	{
3167256d0afbSKees Cook 		EXPECT_EQ(__NR_restart_syscall, ret);
3168256d0afbSKees Cook 	}
3169c99ee51aSKees Cook 
3170256d0afbSKees Cook 	/* Write again to end test. */
3171c99ee51aSKees Cook 	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
3172c99ee51aSKees Cook 	ASSERT_EQ(1, write(pipefd[1], "!", 1));
3173c99ee51aSKees Cook 	EXPECT_EQ(0, close(pipefd[1]));
3174c99ee51aSKees Cook 
3175c99ee51aSKees Cook 	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
3176c99ee51aSKees Cook 	if (WIFSIGNALED(status) || WEXITSTATUS(status))
3177c99ee51aSKees Cook 		_metadata->passed = 0;
3178c99ee51aSKees Cook }
3179c99ee51aSKees Cook 
TEST_SIGNAL(filter_flag_log,SIGSYS)3180e66a3997STyler Hicks TEST_SIGNAL(filter_flag_log, SIGSYS)
3181e66a3997STyler Hicks {
3182e66a3997STyler Hicks 	struct sock_filter allow_filter[] = {
3183e66a3997STyler Hicks 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
3184e66a3997STyler Hicks 	};
3185e66a3997STyler Hicks 	struct sock_filter kill_filter[] = {
3186e66a3997STyler Hicks 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
3187e66a3997STyler Hicks 			offsetof(struct seccomp_data, nr)),
3188e66a3997STyler Hicks 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
3189e66a3997STyler Hicks 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
3190e66a3997STyler Hicks 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
3191e66a3997STyler Hicks 	};
3192e66a3997STyler Hicks 	struct sock_fprog allow_prog = {
3193e66a3997STyler Hicks 		.len = (unsigned short)ARRAY_SIZE(allow_filter),
3194e66a3997STyler Hicks 		.filter = allow_filter,
3195e66a3997STyler Hicks 	};
3196e66a3997STyler Hicks 	struct sock_fprog kill_prog = {
3197e66a3997STyler Hicks 		.len = (unsigned short)ARRAY_SIZE(kill_filter),
3198e66a3997STyler Hicks 		.filter = kill_filter,
3199e66a3997STyler Hicks 	};
3200e66a3997STyler Hicks 	long ret;
3201e66a3997STyler Hicks 	pid_t parent = getppid();
3202e66a3997STyler Hicks 
3203e66a3997STyler Hicks 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3204e66a3997STyler Hicks 	ASSERT_EQ(0, ret);
3205e66a3997STyler Hicks 
3206e66a3997STyler Hicks 	/* Verify that the FILTER_FLAG_LOG flag isn't accepted in strict mode */
3207e66a3997STyler Hicks 	ret = seccomp(SECCOMP_SET_MODE_STRICT, SECCOMP_FILTER_FLAG_LOG,
3208e66a3997STyler Hicks 		      &allow_prog);
3209e66a3997STyler Hicks 	ASSERT_NE(ENOSYS, errno) {
3210e66a3997STyler Hicks 		TH_LOG("Kernel does not support seccomp syscall!");
3211e66a3997STyler Hicks 	}
3212e66a3997STyler Hicks 	EXPECT_NE(0, ret) {
3213e66a3997STyler Hicks 		TH_LOG("Kernel accepted FILTER_FLAG_LOG flag in strict mode!");
3214e66a3997STyler Hicks 	}
3215e66a3997STyler Hicks 	EXPECT_EQ(EINVAL, errno) {
3216e66a3997STyler Hicks 		TH_LOG("Kernel returned unexpected errno for FILTER_FLAG_LOG flag in strict mode!");
3217e66a3997STyler Hicks 	}
3218e66a3997STyler Hicks 
3219e66a3997STyler Hicks 	/* Verify that a simple, permissive filter can be added with no flags */
3220e66a3997STyler Hicks 	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &allow_prog);
3221e66a3997STyler Hicks 	EXPECT_EQ(0, ret);
3222e66a3997STyler Hicks 
3223e66a3997STyler Hicks 	/* See if the same filter can be added with the FILTER_FLAG_LOG flag */
3224e66a3997STyler Hicks 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG,
3225e66a3997STyler Hicks 		      &allow_prog);
3226e66a3997STyler Hicks 	ASSERT_NE(EINVAL, errno) {
3227e66a3997STyler Hicks 		TH_LOG("Kernel does not support the FILTER_FLAG_LOG flag!");
3228e66a3997STyler Hicks 	}
3229e66a3997STyler Hicks 	EXPECT_EQ(0, ret);
3230e66a3997STyler Hicks 
3231e66a3997STyler Hicks 	/* Ensure that the kill filter works with the FILTER_FLAG_LOG flag */
3232e66a3997STyler Hicks 	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG,
3233e66a3997STyler Hicks 		      &kill_prog);
3234e66a3997STyler Hicks 	EXPECT_EQ(0, ret);
3235e66a3997STyler Hicks 
3236e66a3997STyler Hicks 	EXPECT_EQ(parent, syscall(__NR_getppid));
3237e66a3997STyler Hicks 	/* getpid() should never return. */
3238e66a3997STyler Hicks 	EXPECT_EQ(0, syscall(__NR_getpid));
3239e66a3997STyler Hicks }
3240e66a3997STyler Hicks 
TEST(get_action_avail)3241d612b1fdSTyler Hicks TEST(get_action_avail)
3242d612b1fdSTyler Hicks {
3243fd76875cSKees Cook 	__u32 actions[] = { SECCOMP_RET_KILL_THREAD, SECCOMP_RET_TRAP,
3244d612b1fdSTyler Hicks 			    SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE,
324559f5cf44STyler Hicks 			    SECCOMP_RET_LOG,   SECCOMP_RET_ALLOW };
3246d612b1fdSTyler Hicks 	__u32 unknown_action = 0x10000000U;
3247d612b1fdSTyler Hicks 	int i;
3248d612b1fdSTyler Hicks 	long ret;
3249d612b1fdSTyler Hicks 
3250d612b1fdSTyler Hicks 	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[0]);
3251d612b1fdSTyler Hicks 	ASSERT_NE(ENOSYS, errno) {
3252d612b1fdSTyler Hicks 		TH_LOG("Kernel does not support seccomp syscall!");
3253d612b1fdSTyler Hicks 	}
3254d612b1fdSTyler Hicks 	ASSERT_NE(EINVAL, errno) {
3255d612b1fdSTyler Hicks 		TH_LOG("Kernel does not support SECCOMP_GET_ACTION_AVAIL operation!");
3256d612b1fdSTyler Hicks 	}
3257d612b1fdSTyler Hicks 	EXPECT_EQ(ret, 0);
3258d612b1fdSTyler Hicks 
3259d612b1fdSTyler Hicks 	for (i = 0; i < ARRAY_SIZE(actions); i++) {
3260d612b1fdSTyler Hicks 		ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[i]);
3261d612b1fdSTyler Hicks 		EXPECT_EQ(ret, 0) {
3262d612b1fdSTyler Hicks 			TH_LOG("Expected action (0x%X) not available!",
3263d612b1fdSTyler Hicks 			       actions[i]);
3264d612b1fdSTyler Hicks 		}
3265d612b1fdSTyler Hicks 	}
3266d612b1fdSTyler Hicks 
3267d612b1fdSTyler Hicks 	/* Check that an unknown action is handled properly (EOPNOTSUPP) */
3268d612b1fdSTyler Hicks 	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &unknown_action);
3269d612b1fdSTyler Hicks 	EXPECT_EQ(ret, -1);
3270d612b1fdSTyler Hicks 	EXPECT_EQ(errno, EOPNOTSUPP);
3271d612b1fdSTyler Hicks }
3272d612b1fdSTyler Hicks 
TEST(get_metadata)3273d057dc4eSTycho Andersen TEST(get_metadata)
3274d057dc4eSTycho Andersen {
3275d057dc4eSTycho Andersen 	pid_t pid;
3276d057dc4eSTycho Andersen 	int pipefd[2];
3277d057dc4eSTycho Andersen 	char buf;
3278d057dc4eSTycho Andersen 	struct seccomp_metadata md;
32796c3b6d50SKees Cook 	long ret;
3280d057dc4eSTycho Andersen 
32813aa415ddSTycho Andersen 	/* Only real root can get metadata. */
32823aa415ddSTycho Andersen 	if (geteuid()) {
32838b1bc88cSKees Cook 		SKIP(return, "get_metadata requires real root");
32843aa415ddSTycho Andersen 		return;
32853aa415ddSTycho Andersen 	}
32863aa415ddSTycho Andersen 
3287d057dc4eSTycho Andersen 	ASSERT_EQ(0, pipe(pipefd));
3288d057dc4eSTycho Andersen 
3289d057dc4eSTycho Andersen 	pid = fork();
3290d057dc4eSTycho Andersen 	ASSERT_GE(pid, 0);
3291d057dc4eSTycho Andersen 	if (pid == 0) {
3292d057dc4eSTycho Andersen 		struct sock_filter filter[] = {
3293d057dc4eSTycho Andersen 			BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
3294d057dc4eSTycho Andersen 		};
3295d057dc4eSTycho Andersen 		struct sock_fprog prog = {
3296d057dc4eSTycho Andersen 			.len = (unsigned short)ARRAY_SIZE(filter),
3297d057dc4eSTycho Andersen 			.filter = filter,
3298d057dc4eSTycho Andersen 		};
3299d057dc4eSTycho Andersen 
3300d057dc4eSTycho Andersen 		/* one with log, one without */
3301fb024a07STycho Andersen 		EXPECT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER,
3302d057dc4eSTycho Andersen 				     SECCOMP_FILTER_FLAG_LOG, &prog));
3303fb024a07STycho Andersen 		EXPECT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog));
3304d057dc4eSTycho Andersen 
3305fb024a07STycho Andersen 		EXPECT_EQ(0, close(pipefd[0]));
3306d057dc4eSTycho Andersen 		ASSERT_EQ(1, write(pipefd[1], "1", 1));
3307d057dc4eSTycho Andersen 		ASSERT_EQ(0, close(pipefd[1]));
3308d057dc4eSTycho Andersen 
3309d057dc4eSTycho Andersen 		while (1)
3310d057dc4eSTycho Andersen 			sleep(100);
3311d057dc4eSTycho Andersen 	}
3312d057dc4eSTycho Andersen 
3313d057dc4eSTycho Andersen 	ASSERT_EQ(0, close(pipefd[1]));
3314d057dc4eSTycho Andersen 	ASSERT_EQ(1, read(pipefd[0], &buf, 1));
3315d057dc4eSTycho Andersen 
3316d057dc4eSTycho Andersen 	ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid));
3317d057dc4eSTycho Andersen 	ASSERT_EQ(pid, waitpid(pid, NULL, 0));
3318d057dc4eSTycho Andersen 
33196c3b6d50SKees Cook 	/* Past here must not use ASSERT or child process is never killed. */
33206c3b6d50SKees Cook 
3321d057dc4eSTycho Andersen 	md.filter_off = 0;
33226c3b6d50SKees Cook 	errno = 0;
33236c3b6d50SKees Cook 	ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md);
33246c3b6d50SKees Cook 	EXPECT_EQ(sizeof(md), ret) {
33256c3b6d50SKees Cook 		if (errno == EINVAL)
33268b1bc88cSKees Cook 			SKIP(goto skip, "Kernel does not support PTRACE_SECCOMP_GET_METADATA (missing CONFIG_CHECKPOINT_RESTORE?)");
33276c3b6d50SKees Cook 	}
33286c3b6d50SKees Cook 
3329d057dc4eSTycho Andersen 	EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG);
3330d057dc4eSTycho Andersen 	EXPECT_EQ(md.filter_off, 0);
3331d057dc4eSTycho Andersen 
3332d057dc4eSTycho Andersen 	md.filter_off = 1;
33336c3b6d50SKees Cook 	ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md);
33346c3b6d50SKees Cook 	EXPECT_EQ(sizeof(md), ret);
3335d057dc4eSTycho Andersen 	EXPECT_EQ(md.flags, 0);
3336d057dc4eSTycho Andersen 	EXPECT_EQ(md.filter_off, 1);
3337d057dc4eSTycho Andersen 
33386c3b6d50SKees Cook skip:
3339d057dc4eSTycho Andersen 	ASSERT_EQ(0, kill(pid, SIGKILL));
3340d057dc4eSTycho Andersen }
3341d057dc4eSTycho Andersen 
user_notif_syscall(int nr,unsigned int flags)3342279ed890SKees Cook static int user_notif_syscall(int nr, unsigned int flags)
33436a21cc50STycho Andersen {
33446a21cc50STycho Andersen 	struct sock_filter filter[] = {
3345a2304288SZou Wei 		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
33466a21cc50STycho Andersen 			offsetof(struct seccomp_data, nr)),
3347a2304288SZou Wei 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, nr, 0, 1),
3348a2304288SZou Wei 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_USER_NOTIF),
3349a2304288SZou Wei 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
33506a21cc50STycho Andersen 	};
33516a21cc50STycho Andersen 
33526a21cc50STycho Andersen 	struct sock_fprog prog = {
33536a21cc50STycho Andersen 		.len = (unsigned short)ARRAY_SIZE(filter),
33546a21cc50STycho Andersen 		.filter = filter,
33556a21cc50STycho Andersen 	};
33566a21cc50STycho Andersen 
33576a21cc50STycho Andersen 	return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog);
33586a21cc50STycho Andersen }
33596a21cc50STycho Andersen 
3360223e660bSChristian Brauner #define USER_NOTIF_MAGIC INT_MAX
TEST(user_notification_basic)33616a21cc50STycho Andersen TEST(user_notification_basic)
33626a21cc50STycho Andersen {
33636a21cc50STycho Andersen 	pid_t pid;
33646a21cc50STycho Andersen 	long ret;
33656a21cc50STycho Andersen 	int status, listener;
33666a21cc50STycho Andersen 	struct seccomp_notif req = {};
33676a21cc50STycho Andersen 	struct seccomp_notif_resp resp = {};
33686a21cc50STycho Andersen 	struct pollfd pollfd;
33696a21cc50STycho Andersen 
33706a21cc50STycho Andersen 	struct sock_filter filter[] = {
33716a21cc50STycho Andersen 		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
33726a21cc50STycho Andersen 	};
33736a21cc50STycho Andersen 	struct sock_fprog prog = {
33746a21cc50STycho Andersen 		.len = (unsigned short)ARRAY_SIZE(filter),
33756a21cc50STycho Andersen 		.filter = filter,
33766a21cc50STycho Andersen 	};
33776a21cc50STycho Andersen 
3378c7140706STycho Andersen 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3379c7140706STycho Andersen 	ASSERT_EQ(0, ret) {
3380c7140706STycho Andersen 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3381c7140706STycho Andersen 	}
3382c7140706STycho Andersen 
33836a21cc50STycho Andersen 	pid = fork();
33846a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
33856a21cc50STycho Andersen 
33866a21cc50STycho Andersen 	/* Check that we get -ENOSYS with no listener attached */
33876a21cc50STycho Andersen 	if (pid == 0) {
3388279ed890SKees Cook 		if (user_notif_syscall(__NR_getppid, 0) < 0)
33896a21cc50STycho Andersen 			exit(1);
33909dd3fcb0SKees Cook 		ret = syscall(__NR_getppid);
33916a21cc50STycho Andersen 		exit(ret >= 0 || errno != ENOSYS);
33926a21cc50STycho Andersen 	}
33936a21cc50STycho Andersen 
33946a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
33956a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
33966a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
33976a21cc50STycho Andersen 
33980b54b443STycho Andersen 	/* Add some no-op filters for grins. */
33996a21cc50STycho Andersen 	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
34006a21cc50STycho Andersen 	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
34016a21cc50STycho Andersen 	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
34026a21cc50STycho Andersen 	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
34036a21cc50STycho Andersen 
34046a21cc50STycho Andersen 	/* Check that the basic notification machinery works */
3405279ed890SKees Cook 	listener = user_notif_syscall(__NR_getppid,
34066a21cc50STycho Andersen 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
34073d244c19SKees Cook 	ASSERT_GE(listener, 0);
34086a21cc50STycho Andersen 
34096a21cc50STycho Andersen 	/* Installing a second listener in the chain should EBUSY */
3410279ed890SKees Cook 	EXPECT_EQ(user_notif_syscall(__NR_getppid,
34116a21cc50STycho Andersen 				     SECCOMP_FILTER_FLAG_NEW_LISTENER),
34126a21cc50STycho Andersen 		  -1);
34136a21cc50STycho Andersen 	EXPECT_EQ(errno, EBUSY);
34146a21cc50STycho Andersen 
34156a21cc50STycho Andersen 	pid = fork();
34166a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
34176a21cc50STycho Andersen 
34186a21cc50STycho Andersen 	if (pid == 0) {
34199dd3fcb0SKees Cook 		ret = syscall(__NR_getppid);
34206a21cc50STycho Andersen 		exit(ret != USER_NOTIF_MAGIC);
34216a21cc50STycho Andersen 	}
34226a21cc50STycho Andersen 
34236a21cc50STycho Andersen 	pollfd.fd = listener;
34246a21cc50STycho Andersen 	pollfd.events = POLLIN | POLLOUT;
34256a21cc50STycho Andersen 
34266a21cc50STycho Andersen 	EXPECT_GT(poll(&pollfd, 1, -1), 0);
34276a21cc50STycho Andersen 	EXPECT_EQ(pollfd.revents, POLLIN);
34286a21cc50STycho Andersen 
3429e4ab5cccSSargun Dhillon 	/* Test that we can't pass garbage to the kernel. */
3430e4ab5cccSSargun Dhillon 	memset(&req, 0, sizeof(req));
3431e4ab5cccSSargun Dhillon 	req.pid = -1;
3432e4ab5cccSSargun Dhillon 	errno = 0;
3433e4ab5cccSSargun Dhillon 	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req);
3434e4ab5cccSSargun Dhillon 	EXPECT_EQ(-1, ret);
3435e4ab5cccSSargun Dhillon 	EXPECT_EQ(EINVAL, errno);
3436e4ab5cccSSargun Dhillon 
3437e4ab5cccSSargun Dhillon 	if (ret) {
3438e4ab5cccSSargun Dhillon 		req.pid = 0;
34396a21cc50STycho Andersen 		EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
3440e4ab5cccSSargun Dhillon 	}
34416a21cc50STycho Andersen 
34426a21cc50STycho Andersen 	pollfd.fd = listener;
34436a21cc50STycho Andersen 	pollfd.events = POLLIN | POLLOUT;
34446a21cc50STycho Andersen 
34456a21cc50STycho Andersen 	EXPECT_GT(poll(&pollfd, 1, -1), 0);
34466a21cc50STycho Andersen 	EXPECT_EQ(pollfd.revents, POLLOUT);
34476a21cc50STycho Andersen 
34489dd3fcb0SKees Cook 	EXPECT_EQ(req.data.nr,  __NR_getppid);
34496a21cc50STycho Andersen 
34506a21cc50STycho Andersen 	resp.id = req.id;
34516a21cc50STycho Andersen 	resp.error = 0;
34526a21cc50STycho Andersen 	resp.val = USER_NOTIF_MAGIC;
34536a21cc50STycho Andersen 
34546a21cc50STycho Andersen 	/* check that we make sure flags == 0 */
34556a21cc50STycho Andersen 	resp.flags = 1;
34566a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
34576a21cc50STycho Andersen 	EXPECT_EQ(errno, EINVAL);
34586a21cc50STycho Andersen 
34596a21cc50STycho Andersen 	resp.flags = 0;
34606a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
34616a21cc50STycho Andersen 
34626a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
34636a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
34646a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
34656a21cc50STycho Andersen }
34666a21cc50STycho Andersen 
TEST(user_notification_with_tsync)346751891498STycho Andersen TEST(user_notification_with_tsync)
346851891498STycho Andersen {
346951891498STycho Andersen 	int ret;
347051891498STycho Andersen 	unsigned int flags;
347151891498STycho Andersen 
3472e4d05028SKees Cook 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3473e4d05028SKees Cook 	ASSERT_EQ(0, ret) {
3474e4d05028SKees Cook 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3475e4d05028SKees Cook 	}
3476e4d05028SKees Cook 
347751891498STycho Andersen 	/* these were exclusive */
347851891498STycho Andersen 	flags = SECCOMP_FILTER_FLAG_NEW_LISTENER |
347951891498STycho Andersen 		SECCOMP_FILTER_FLAG_TSYNC;
3480279ed890SKees Cook 	ASSERT_EQ(-1, user_notif_syscall(__NR_getppid, flags));
348151891498STycho Andersen 	ASSERT_EQ(EINVAL, errno);
348251891498STycho Andersen 
348351891498STycho Andersen 	/* but now they're not */
348451891498STycho Andersen 	flags |= SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
3485279ed890SKees Cook 	ret = user_notif_syscall(__NR_getppid, flags);
348651891498STycho Andersen 	close(ret);
348751891498STycho Andersen 	ASSERT_LE(0, ret);
348851891498STycho Andersen }
348951891498STycho Andersen 
TEST(user_notification_kill_in_middle)34906a21cc50STycho Andersen TEST(user_notification_kill_in_middle)
34916a21cc50STycho Andersen {
34926a21cc50STycho Andersen 	pid_t pid;
34936a21cc50STycho Andersen 	long ret;
34946a21cc50STycho Andersen 	int listener;
34956a21cc50STycho Andersen 	struct seccomp_notif req = {};
34966a21cc50STycho Andersen 	struct seccomp_notif_resp resp = {};
34976a21cc50STycho Andersen 
3498c7140706STycho Andersen 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3499c7140706STycho Andersen 	ASSERT_EQ(0, ret) {
3500c7140706STycho Andersen 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3501c7140706STycho Andersen 	}
3502c7140706STycho Andersen 
3503279ed890SKees Cook 	listener = user_notif_syscall(__NR_getppid,
35046a21cc50STycho Andersen 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
35053d244c19SKees Cook 	ASSERT_GE(listener, 0);
35066a21cc50STycho Andersen 
35076a21cc50STycho Andersen 	/*
35086a21cc50STycho Andersen 	 * Check that nothing bad happens when we kill the task in the middle
35096a21cc50STycho Andersen 	 * of a syscall.
35106a21cc50STycho Andersen 	 */
35116a21cc50STycho Andersen 	pid = fork();
35126a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
35136a21cc50STycho Andersen 
35146a21cc50STycho Andersen 	if (pid == 0) {
35159dd3fcb0SKees Cook 		ret = syscall(__NR_getppid);
35166a21cc50STycho Andersen 		exit(ret != USER_NOTIF_MAGIC);
35176a21cc50STycho Andersen 	}
35186a21cc50STycho Andersen 
35196a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
35206a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), 0);
35216a21cc50STycho Andersen 
35226a21cc50STycho Andersen 	EXPECT_EQ(kill(pid, SIGKILL), 0);
35236a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, NULL, 0), pid);
35246a21cc50STycho Andersen 
35256a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), -1);
35266a21cc50STycho Andersen 
35276a21cc50STycho Andersen 	resp.id = req.id;
35286a21cc50STycho Andersen 	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
35296a21cc50STycho Andersen 	EXPECT_EQ(ret, -1);
35306a21cc50STycho Andersen 	EXPECT_EQ(errno, ENOENT);
35316a21cc50STycho Andersen }
35326a21cc50STycho Andersen 
35336a21cc50STycho Andersen static int handled = -1;
35346a21cc50STycho Andersen 
signal_handler(int signal)35356a21cc50STycho Andersen static void signal_handler(int signal)
35366a21cc50STycho Andersen {
35376a21cc50STycho Andersen 	if (write(handled, "c", 1) != 1)
35386a21cc50STycho Andersen 		perror("write from signal");
35396a21cc50STycho Andersen }
35406a21cc50STycho Andersen 
TEST(user_notification_signal)35416a21cc50STycho Andersen TEST(user_notification_signal)
35426a21cc50STycho Andersen {
35436a21cc50STycho Andersen 	pid_t pid;
35446a21cc50STycho Andersen 	long ret;
35456a21cc50STycho Andersen 	int status, listener, sk_pair[2];
35466a21cc50STycho Andersen 	struct seccomp_notif req = {};
35476a21cc50STycho Andersen 	struct seccomp_notif_resp resp = {};
35486a21cc50STycho Andersen 	char c;
35496a21cc50STycho Andersen 
3550c7140706STycho Andersen 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3551c7140706STycho Andersen 	ASSERT_EQ(0, ret) {
3552c7140706STycho Andersen 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3553c7140706STycho Andersen 	}
3554c7140706STycho Andersen 
35556a21cc50STycho Andersen 	ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
35566a21cc50STycho Andersen 
3557279ed890SKees Cook 	listener = user_notif_syscall(__NR_gettid,
35586a21cc50STycho Andersen 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
35593d244c19SKees Cook 	ASSERT_GE(listener, 0);
35606a21cc50STycho Andersen 
35616a21cc50STycho Andersen 	pid = fork();
35626a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
35636a21cc50STycho Andersen 
35646a21cc50STycho Andersen 	if (pid == 0) {
35656a21cc50STycho Andersen 		close(sk_pair[0]);
35666a21cc50STycho Andersen 		handled = sk_pair[1];
35676a21cc50STycho Andersen 		if (signal(SIGUSR1, signal_handler) == SIG_ERR) {
35686a21cc50STycho Andersen 			perror("signal");
35696a21cc50STycho Andersen 			exit(1);
35706a21cc50STycho Andersen 		}
35716a21cc50STycho Andersen 		/*
35726a21cc50STycho Andersen 		 * ERESTARTSYS behavior is a bit hard to test, because we need
35736a21cc50STycho Andersen 		 * to rely on a signal that has not yet been handled. Let's at
35746a21cc50STycho Andersen 		 * least check that the error code gets propagated through, and
35756a21cc50STycho Andersen 		 * hope that it doesn't break when there is actually a signal :)
35766a21cc50STycho Andersen 		 */
35776a21cc50STycho Andersen 		ret = syscall(__NR_gettid);
35786a21cc50STycho Andersen 		exit(!(ret == -1 && errno == 512));
35796a21cc50STycho Andersen 	}
35806a21cc50STycho Andersen 
35816a21cc50STycho Andersen 	close(sk_pair[1]);
35826a21cc50STycho Andersen 
358388c13f8bSSargun Dhillon 	memset(&req, 0, sizeof(req));
35846a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
35856a21cc50STycho Andersen 
35866a21cc50STycho Andersen 	EXPECT_EQ(kill(pid, SIGUSR1), 0);
35876a21cc50STycho Andersen 
35886a21cc50STycho Andersen 	/*
35896a21cc50STycho Andersen 	 * Make sure the signal really is delivered, which means we're not
35906a21cc50STycho Andersen 	 * stuck in the user notification code any more and the notification
35916a21cc50STycho Andersen 	 * should be dead.
35926a21cc50STycho Andersen 	 */
35936a21cc50STycho Andersen 	EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
35946a21cc50STycho Andersen 
35956a21cc50STycho Andersen 	resp.id = req.id;
35966a21cc50STycho Andersen 	resp.error = -EPERM;
35976a21cc50STycho Andersen 	resp.val = 0;
35986a21cc50STycho Andersen 
35996a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
36006a21cc50STycho Andersen 	EXPECT_EQ(errno, ENOENT);
36016a21cc50STycho Andersen 
360288c13f8bSSargun Dhillon 	memset(&req, 0, sizeof(req));
36036a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
36046a21cc50STycho Andersen 
36056a21cc50STycho Andersen 	resp.id = req.id;
36066a21cc50STycho Andersen 	resp.error = -512; /* -ERESTARTSYS */
36076a21cc50STycho Andersen 	resp.val = 0;
36086a21cc50STycho Andersen 
36096a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
36106a21cc50STycho Andersen 
36116a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
36126a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
36136a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
36146a21cc50STycho Andersen }
36156a21cc50STycho Andersen 
TEST(user_notification_closed_listener)36166a21cc50STycho Andersen TEST(user_notification_closed_listener)
36176a21cc50STycho Andersen {
36186a21cc50STycho Andersen 	pid_t pid;
36196a21cc50STycho Andersen 	long ret;
36206a21cc50STycho Andersen 	int status, listener;
36216a21cc50STycho Andersen 
3622c7140706STycho Andersen 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3623c7140706STycho Andersen 	ASSERT_EQ(0, ret) {
3624c7140706STycho Andersen 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3625c7140706STycho Andersen 	}
3626c7140706STycho Andersen 
3627279ed890SKees Cook 	listener = user_notif_syscall(__NR_getppid,
36286a21cc50STycho Andersen 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
36293d244c19SKees Cook 	ASSERT_GE(listener, 0);
36306a21cc50STycho Andersen 
36316a21cc50STycho Andersen 	/*
36326a21cc50STycho Andersen 	 * Check that we get an ENOSYS when the listener is closed.
36336a21cc50STycho Andersen 	 */
36346a21cc50STycho Andersen 	pid = fork();
36356a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
36366a21cc50STycho Andersen 	if (pid == 0) {
36376a21cc50STycho Andersen 		close(listener);
36389dd3fcb0SKees Cook 		ret = syscall(__NR_getppid);
36396a21cc50STycho Andersen 		exit(ret != -1 && errno != ENOSYS);
36406a21cc50STycho Andersen 	}
36416a21cc50STycho Andersen 
36426a21cc50STycho Andersen 	close(listener);
36436a21cc50STycho Andersen 
36446a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
36456a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
36466a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
36476a21cc50STycho Andersen }
36486a21cc50STycho Andersen 
36496a21cc50STycho Andersen /*
36506a21cc50STycho Andersen  * Check that a pid in a child namespace still shows up as valid in ours.
36516a21cc50STycho Andersen  */
TEST(user_notification_child_pid_ns)36526a21cc50STycho Andersen TEST(user_notification_child_pid_ns)
36536a21cc50STycho Andersen {
36546a21cc50STycho Andersen 	pid_t pid;
36556a21cc50STycho Andersen 	int status, listener;
36566a21cc50STycho Andersen 	struct seccomp_notif req = {};
36576a21cc50STycho Andersen 	struct seccomp_notif_resp resp = {};
36586a21cc50STycho Andersen 
3659d7d2e5bbSKees Cook 	ASSERT_EQ(unshare(CLONE_NEWUSER | CLONE_NEWPID), 0) {
3660d7d2e5bbSKees Cook 		if (errno == EINVAL)
3661d7d2e5bbSKees Cook 			SKIP(return, "kernel missing CLONE_NEWUSER support");
3662d7d2e5bbSKees Cook 	};
36636a21cc50STycho Andersen 
3664279ed890SKees Cook 	listener = user_notif_syscall(__NR_getppid,
36659dd3fcb0SKees Cook 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
36666a21cc50STycho Andersen 	ASSERT_GE(listener, 0);
36676a21cc50STycho Andersen 
36686a21cc50STycho Andersen 	pid = fork();
36696a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
36706a21cc50STycho Andersen 
36716a21cc50STycho Andersen 	if (pid == 0)
36729dd3fcb0SKees Cook 		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
36736a21cc50STycho Andersen 
36746a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
36756a21cc50STycho Andersen 	EXPECT_EQ(req.pid, pid);
36766a21cc50STycho Andersen 
36776a21cc50STycho Andersen 	resp.id = req.id;
36786a21cc50STycho Andersen 	resp.error = 0;
36796a21cc50STycho Andersen 	resp.val = USER_NOTIF_MAGIC;
36806a21cc50STycho Andersen 
36816a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
36826a21cc50STycho Andersen 
36836a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
36846a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
36856a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
36866a21cc50STycho Andersen 	close(listener);
36876a21cc50STycho Andersen }
36886a21cc50STycho Andersen 
36896a21cc50STycho Andersen /*
36906a21cc50STycho Andersen  * Check that a pid in a sibling (i.e. unrelated) namespace shows up as 0, i.e.
36916a21cc50STycho Andersen  * invalid.
36926a21cc50STycho Andersen  */
TEST(user_notification_sibling_pid_ns)36936a21cc50STycho Andersen TEST(user_notification_sibling_pid_ns)
36946a21cc50STycho Andersen {
36956a21cc50STycho Andersen 	pid_t pid, pid2;
36966a21cc50STycho Andersen 	int status, listener;
36976a21cc50STycho Andersen 	struct seccomp_notif req = {};
36986a21cc50STycho Andersen 	struct seccomp_notif_resp resp = {};
36996a21cc50STycho Andersen 
3700c7140706STycho Andersen 	ASSERT_EQ(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), 0) {
3701c7140706STycho Andersen 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3702c7140706STycho Andersen 	}
3703c7140706STycho Andersen 
3704279ed890SKees Cook 	listener = user_notif_syscall(__NR_getppid,
37059dd3fcb0SKees Cook 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
37066a21cc50STycho Andersen 	ASSERT_GE(listener, 0);
37076a21cc50STycho Andersen 
37086a21cc50STycho Andersen 	pid = fork();
37096a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
37106a21cc50STycho Andersen 
37116a21cc50STycho Andersen 	if (pid == 0) {
3712612fbf65STerry Tritton 		ASSERT_EQ(unshare(CLONE_NEWPID), 0) {
3713612fbf65STerry Tritton 			if (errno == EPERM)
3714612fbf65STerry Tritton 				SKIP(return, "CLONE_NEWPID requires CAP_SYS_ADMIN");
3715612fbf65STerry Tritton 			else if (errno == EINVAL)
3716612fbf65STerry Tritton 				SKIP(return, "CLONE_NEWPID is invalid (missing CONFIG_PID_NS?)");
3717612fbf65STerry Tritton 		}
37186a21cc50STycho Andersen 
37196a21cc50STycho Andersen 		pid2 = fork();
37206a21cc50STycho Andersen 		ASSERT_GE(pid2, 0);
37216a21cc50STycho Andersen 
37226a21cc50STycho Andersen 		if (pid2 == 0)
37239dd3fcb0SKees Cook 			exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
37246a21cc50STycho Andersen 
37256a21cc50STycho Andersen 		EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
37266a21cc50STycho Andersen 		EXPECT_EQ(true, WIFEXITED(status));
37276a21cc50STycho Andersen 		EXPECT_EQ(0, WEXITSTATUS(status));
37286a21cc50STycho Andersen 		exit(WEXITSTATUS(status));
37296a21cc50STycho Andersen 	}
37306a21cc50STycho Andersen 
37316a21cc50STycho Andersen 	/* Create the sibling ns, and sibling in it. */
3732d7d2e5bbSKees Cook 	ASSERT_EQ(unshare(CLONE_NEWPID), 0) {
3733d7d2e5bbSKees Cook 		if (errno == EPERM)
3734d7d2e5bbSKees Cook 			SKIP(return, "CLONE_NEWPID requires CAP_SYS_ADMIN");
3735612fbf65STerry Tritton 		else if (errno == EINVAL)
3736612fbf65STerry Tritton 			SKIP(return, "CLONE_NEWPID is invalid (missing CONFIG_PID_NS?)");
3737d7d2e5bbSKees Cook 	}
37389dd3fcb0SKees Cook 	ASSERT_EQ(errno, 0);
37396a21cc50STycho Andersen 
37406a21cc50STycho Andersen 	pid2 = fork();
37419dd3fcb0SKees Cook 	ASSERT_GE(pid2, 0);
37426a21cc50STycho Andersen 
37436a21cc50STycho Andersen 	if (pid2 == 0) {
37446a21cc50STycho Andersen 		ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
37456a21cc50STycho Andersen 		/*
37466a21cc50STycho Andersen 		 * The pid should be 0, i.e. the task is in some namespace that
37476a21cc50STycho Andersen 		 * we can't "see".
37486a21cc50STycho Andersen 		 */
37499dd3fcb0SKees Cook 		EXPECT_EQ(req.pid, 0);
37506a21cc50STycho Andersen 
37516a21cc50STycho Andersen 		resp.id = req.id;
37526a21cc50STycho Andersen 		resp.error = 0;
37536a21cc50STycho Andersen 		resp.val = USER_NOTIF_MAGIC;
37546a21cc50STycho Andersen 
37556a21cc50STycho Andersen 		ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
37566a21cc50STycho Andersen 		exit(0);
37576a21cc50STycho Andersen 	}
37586a21cc50STycho Andersen 
37596a21cc50STycho Andersen 	close(listener);
37606a21cc50STycho Andersen 
37616a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
37626a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
37636a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
37646a21cc50STycho Andersen 
37656a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
37666a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
37676a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
37686a21cc50STycho Andersen }
37696a21cc50STycho Andersen 
TEST(user_notification_fault_recv)37706a21cc50STycho Andersen TEST(user_notification_fault_recv)
37716a21cc50STycho Andersen {
37726a21cc50STycho Andersen 	pid_t pid;
37736a21cc50STycho Andersen 	int status, listener;
37746a21cc50STycho Andersen 	struct seccomp_notif req = {};
37756a21cc50STycho Andersen 	struct seccomp_notif_resp resp = {};
37766a21cc50STycho Andersen 
377795a126d9SYang Guang 	ASSERT_EQ(unshare(CLONE_NEWUSER), 0) {
377895a126d9SYang Guang 		if (errno == EINVAL)
377995a126d9SYang Guang 			SKIP(return, "kernel missing CLONE_NEWUSER support");
378095a126d9SYang Guang 	}
378130d53a58STycho Andersen 
3782279ed890SKees Cook 	listener = user_notif_syscall(__NR_getppid,
37839dd3fcb0SKees Cook 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
37846a21cc50STycho Andersen 	ASSERT_GE(listener, 0);
37856a21cc50STycho Andersen 
37866a21cc50STycho Andersen 	pid = fork();
37876a21cc50STycho Andersen 	ASSERT_GE(pid, 0);
37886a21cc50STycho Andersen 
37896a21cc50STycho Andersen 	if (pid == 0)
37909dd3fcb0SKees Cook 		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
37916a21cc50STycho Andersen 
37926a21cc50STycho Andersen 	/* Do a bad recv() */
37936a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, NULL), -1);
37946a21cc50STycho Andersen 	EXPECT_EQ(errno, EFAULT);
37956a21cc50STycho Andersen 
37966a21cc50STycho Andersen 	/* We should still be able to receive this notification, though. */
37976a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
37986a21cc50STycho Andersen 	EXPECT_EQ(req.pid, pid);
37996a21cc50STycho Andersen 
38006a21cc50STycho Andersen 	resp.id = req.id;
38016a21cc50STycho Andersen 	resp.error = 0;
38026a21cc50STycho Andersen 	resp.val = USER_NOTIF_MAGIC;
38036a21cc50STycho Andersen 
38046a21cc50STycho Andersen 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
38056a21cc50STycho Andersen 
38066a21cc50STycho Andersen 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
38076a21cc50STycho Andersen 	EXPECT_EQ(true, WIFEXITED(status));
38086a21cc50STycho Andersen 	EXPECT_EQ(0, WEXITSTATUS(status));
38096a21cc50STycho Andersen }
38106a21cc50STycho Andersen 
TEST(seccomp_get_notif_sizes)38116a21cc50STycho Andersen TEST(seccomp_get_notif_sizes)
38126a21cc50STycho Andersen {
38136a21cc50STycho Andersen 	struct seccomp_notif_sizes sizes;
38146a21cc50STycho Andersen 
38153d244c19SKees Cook 	ASSERT_EQ(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes), 0);
38166a21cc50STycho Andersen 	EXPECT_EQ(sizes.seccomp_notif, sizeof(struct seccomp_notif));
38176a21cc50STycho Andersen 	EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
38186a21cc50STycho Andersen }
38196a21cc50STycho Andersen 
TEST(user_notification_continue)38200eebfed2SChristian Brauner TEST(user_notification_continue)
38210eebfed2SChristian Brauner {
38220eebfed2SChristian Brauner 	pid_t pid;
38230eebfed2SChristian Brauner 	long ret;
38240eebfed2SChristian Brauner 	int status, listener;
38250eebfed2SChristian Brauner 	struct seccomp_notif req = {};
38260eebfed2SChristian Brauner 	struct seccomp_notif_resp resp = {};
38270eebfed2SChristian Brauner 	struct pollfd pollfd;
38280eebfed2SChristian Brauner 
38290eebfed2SChristian Brauner 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
38300eebfed2SChristian Brauner 	ASSERT_EQ(0, ret) {
38310eebfed2SChristian Brauner 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
38320eebfed2SChristian Brauner 	}
38330eebfed2SChristian Brauner 
3834279ed890SKees Cook 	listener = user_notif_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
38350eebfed2SChristian Brauner 	ASSERT_GE(listener, 0);
38360eebfed2SChristian Brauner 
38370eebfed2SChristian Brauner 	pid = fork();
38380eebfed2SChristian Brauner 	ASSERT_GE(pid, 0);
38390eebfed2SChristian Brauner 
38400eebfed2SChristian Brauner 	if (pid == 0) {
38410eebfed2SChristian Brauner 		int dup_fd, pipe_fds[2];
38420eebfed2SChristian Brauner 		pid_t self;
38430eebfed2SChristian Brauner 
3844cf8918dbSKees Cook 		ASSERT_GE(pipe(pipe_fds), 0);
38450eebfed2SChristian Brauner 
38460eebfed2SChristian Brauner 		dup_fd = dup(pipe_fds[0]);
3847cf8918dbSKees Cook 		ASSERT_GE(dup_fd, 0);
3848cf8918dbSKees Cook 		EXPECT_NE(pipe_fds[0], dup_fd);
38490eebfed2SChristian Brauner 
38500eebfed2SChristian Brauner 		self = getpid();
3851cf8918dbSKees Cook 		ASSERT_EQ(filecmp(self, self, pipe_fds[0], dup_fd), 0);
38520eebfed2SChristian Brauner 		exit(0);
38530eebfed2SChristian Brauner 	}
38540eebfed2SChristian Brauner 
38550eebfed2SChristian Brauner 	pollfd.fd = listener;
38560eebfed2SChristian Brauner 	pollfd.events = POLLIN | POLLOUT;
38570eebfed2SChristian Brauner 
38580eebfed2SChristian Brauner 	EXPECT_GT(poll(&pollfd, 1, -1), 0);
38590eebfed2SChristian Brauner 	EXPECT_EQ(pollfd.revents, POLLIN);
38600eebfed2SChristian Brauner 
38610eebfed2SChristian Brauner 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
38620eebfed2SChristian Brauner 
38630eebfed2SChristian Brauner 	pollfd.fd = listener;
38640eebfed2SChristian Brauner 	pollfd.events = POLLIN | POLLOUT;
38650eebfed2SChristian Brauner 
38660eebfed2SChristian Brauner 	EXPECT_GT(poll(&pollfd, 1, -1), 0);
38670eebfed2SChristian Brauner 	EXPECT_EQ(pollfd.revents, POLLOUT);
38680eebfed2SChristian Brauner 
38690eebfed2SChristian Brauner 	EXPECT_EQ(req.data.nr, __NR_dup);
38700eebfed2SChristian Brauner 
38710eebfed2SChristian Brauner 	resp.id = req.id;
38720eebfed2SChristian Brauner 	resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE;
38730eebfed2SChristian Brauner 
38740eebfed2SChristian Brauner 	/*
38750eebfed2SChristian Brauner 	 * Verify that setting SECCOMP_USER_NOTIF_FLAG_CONTINUE enforces other
38760eebfed2SChristian Brauner 	 * args be set to 0.
38770eebfed2SChristian Brauner 	 */
38780eebfed2SChristian Brauner 	resp.error = 0;
38790eebfed2SChristian Brauner 	resp.val = USER_NOTIF_MAGIC;
38800eebfed2SChristian Brauner 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
38810eebfed2SChristian Brauner 	EXPECT_EQ(errno, EINVAL);
38820eebfed2SChristian Brauner 
38830eebfed2SChristian Brauner 	resp.error = USER_NOTIF_MAGIC;
38840eebfed2SChristian Brauner 	resp.val = 0;
38850eebfed2SChristian Brauner 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
38860eebfed2SChristian Brauner 	EXPECT_EQ(errno, EINVAL);
38870eebfed2SChristian Brauner 
38880eebfed2SChristian Brauner 	resp.error = 0;
38890eebfed2SChristian Brauner 	resp.val = 0;
38900eebfed2SChristian Brauner 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0) {
38910eebfed2SChristian Brauner 		if (errno == EINVAL)
38928b1bc88cSKees Cook 			SKIP(goto skip, "Kernel does not support SECCOMP_USER_NOTIF_FLAG_CONTINUE");
38930eebfed2SChristian Brauner 	}
38940eebfed2SChristian Brauner 
38950eebfed2SChristian Brauner skip:
38960eebfed2SChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
38970eebfed2SChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
38980eebfed2SChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status)) {
38990eebfed2SChristian Brauner 		if (WEXITSTATUS(status) == 2) {
39008b1bc88cSKees Cook 			SKIP(return, "Kernel does not support kcmp() syscall");
39010eebfed2SChristian Brauner 			return;
39020eebfed2SChristian Brauner 		}
39030eebfed2SChristian Brauner 	}
39040eebfed2SChristian Brauner }
39050eebfed2SChristian Brauner 
TEST(user_notification_filter_empty)3906ad568218SChristian Brauner TEST(user_notification_filter_empty)
3907ad568218SChristian Brauner {
3908ad568218SChristian Brauner 	pid_t pid;
3909ad568218SChristian Brauner 	long ret;
3910ad568218SChristian Brauner 	int status;
3911ad568218SChristian Brauner 	struct pollfd pollfd;
3912e953aeaaSKees Cook 	struct __clone_args args = {
3913ad568218SChristian Brauner 		.flags = CLONE_FILES,
3914ad568218SChristian Brauner 		.exit_signal = SIGCHLD,
3915ad568218SChristian Brauner 	};
3916ad568218SChristian Brauner 
3917ad568218SChristian Brauner 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3918ad568218SChristian Brauner 	ASSERT_EQ(0, ret) {
3919ad568218SChristian Brauner 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3920ad568218SChristian Brauner 	}
3921ad568218SChristian Brauner 
3922fbc5d382SKees Cook 	if (__NR_clone3 < 0)
3923fbc5d382SKees Cook 		SKIP(return, "Test not built with clone3 support");
3924fbc5d382SKees Cook 
3925ad568218SChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
3926ad568218SChristian Brauner 	ASSERT_GE(pid, 0);
3927ad568218SChristian Brauner 
3928ad568218SChristian Brauner 	if (pid == 0) {
3929ad568218SChristian Brauner 		int listener;
3930ad568218SChristian Brauner 
393105b52c66SKees Cook 		listener = user_notif_syscall(__NR_mknodat, SECCOMP_FILTER_FLAG_NEW_LISTENER);
3932ad568218SChristian Brauner 		if (listener < 0)
3933ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
3934ad568218SChristian Brauner 
3935ad568218SChristian Brauner 		if (dup2(listener, 200) != 200)
3936ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
3937ad568218SChristian Brauner 
3938ad568218SChristian Brauner 		close(listener);
3939ad568218SChristian Brauner 
3940ad568218SChristian Brauner 		_exit(EXIT_SUCCESS);
3941ad568218SChristian Brauner 	}
3942ad568218SChristian Brauner 
3943ad568218SChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
3944ad568218SChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
3945ad568218SChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
3946ad568218SChristian Brauner 
3947ad568218SChristian Brauner 	/*
3948ad568218SChristian Brauner 	 * The seccomp filter has become unused so we should be notified once
3949ad568218SChristian Brauner 	 * the kernel gets around to cleaning up task struct.
3950ad568218SChristian Brauner 	 */
3951ad568218SChristian Brauner 	pollfd.fd = 200;
3952ad568218SChristian Brauner 	pollfd.events = POLLHUP;
3953ad568218SChristian Brauner 
3954ad568218SChristian Brauner 	EXPECT_GT(poll(&pollfd, 1, 2000), 0);
3955ad568218SChristian Brauner 	EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
3956ad568218SChristian Brauner }
3957ad568218SChristian Brauner 
do_thread(void * data)3958ad568218SChristian Brauner static void *do_thread(void *data)
3959ad568218SChristian Brauner {
3960ad568218SChristian Brauner 	return NULL;
3961ad568218SChristian Brauner }
3962ad568218SChristian Brauner 
TEST(user_notification_filter_empty_threaded)3963ad568218SChristian Brauner TEST(user_notification_filter_empty_threaded)
3964ad568218SChristian Brauner {
3965ad568218SChristian Brauner 	pid_t pid;
3966ad568218SChristian Brauner 	long ret;
3967ad568218SChristian Brauner 	int status;
3968ad568218SChristian Brauner 	struct pollfd pollfd;
3969e953aeaaSKees Cook 	struct __clone_args args = {
3970ad568218SChristian Brauner 		.flags = CLONE_FILES,
3971ad568218SChristian Brauner 		.exit_signal = SIGCHLD,
3972ad568218SChristian Brauner 	};
3973ad568218SChristian Brauner 
3974ad568218SChristian Brauner 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3975ad568218SChristian Brauner 	ASSERT_EQ(0, ret) {
3976ad568218SChristian Brauner 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3977ad568218SChristian Brauner 	}
3978ad568218SChristian Brauner 
3979fbc5d382SKees Cook 	if (__NR_clone3 < 0)
3980fbc5d382SKees Cook 		SKIP(return, "Test not built with clone3 support");
3981fbc5d382SKees Cook 
3982ad568218SChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
3983ad568218SChristian Brauner 	ASSERT_GE(pid, 0);
3984ad568218SChristian Brauner 
3985ad568218SChristian Brauner 	if (pid == 0) {
3986ad568218SChristian Brauner 		pid_t pid1, pid2;
3987ad568218SChristian Brauner 		int listener, status;
3988ad568218SChristian Brauner 		pthread_t thread;
3989ad568218SChristian Brauner 
3990279ed890SKees Cook 		listener = user_notif_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
3991ad568218SChristian Brauner 		if (listener < 0)
3992ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
3993ad568218SChristian Brauner 
3994ad568218SChristian Brauner 		if (dup2(listener, 200) != 200)
3995ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
3996ad568218SChristian Brauner 
3997ad568218SChristian Brauner 		close(listener);
3998ad568218SChristian Brauner 
3999ad568218SChristian Brauner 		pid1 = fork();
4000ad568218SChristian Brauner 		if (pid1 < 0)
4001ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
4002ad568218SChristian Brauner 
4003ad568218SChristian Brauner 		if (pid1 == 0)
4004ad568218SChristian Brauner 			_exit(EXIT_SUCCESS);
4005ad568218SChristian Brauner 
4006ad568218SChristian Brauner 		pid2 = fork();
4007ad568218SChristian Brauner 		if (pid2 < 0)
4008ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
4009ad568218SChristian Brauner 
4010ad568218SChristian Brauner 		if (pid2 == 0)
4011ad568218SChristian Brauner 			_exit(EXIT_SUCCESS);
4012ad568218SChristian Brauner 
4013ad568218SChristian Brauner 		if (pthread_create(&thread, NULL, do_thread, NULL) ||
4014ad568218SChristian Brauner 		    pthread_join(thread, NULL))
4015ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
4016ad568218SChristian Brauner 
4017ad568218SChristian Brauner 		if (pthread_create(&thread, NULL, do_thread, NULL) ||
4018ad568218SChristian Brauner 		    pthread_join(thread, NULL))
4019ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
4020ad568218SChristian Brauner 
4021ad568218SChristian Brauner 		if (waitpid(pid1, &status, 0) != pid1 || !WIFEXITED(status) ||
4022ad568218SChristian Brauner 		    WEXITSTATUS(status))
4023ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
4024ad568218SChristian Brauner 
4025ad568218SChristian Brauner 		if (waitpid(pid2, &status, 0) != pid2 || !WIFEXITED(status) ||
4026ad568218SChristian Brauner 		    WEXITSTATUS(status))
4027ad568218SChristian Brauner 			_exit(EXIT_FAILURE);
4028ad568218SChristian Brauner 
4029ad568218SChristian Brauner 		exit(EXIT_SUCCESS);
4030ad568218SChristian Brauner 	}
4031ad568218SChristian Brauner 
4032ad568218SChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
4033ad568218SChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
4034ad568218SChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
4035ad568218SChristian Brauner 
4036ad568218SChristian Brauner 	/*
4037ad568218SChristian Brauner 	 * The seccomp filter has become unused so we should be notified once
4038ad568218SChristian Brauner 	 * the kernel gets around to cleaning up task struct.
4039ad568218SChristian Brauner 	 */
4040ad568218SChristian Brauner 	pollfd.fd = 200;
4041ad568218SChristian Brauner 	pollfd.events = POLLHUP;
4042ad568218SChristian Brauner 
4043ad568218SChristian Brauner 	EXPECT_GT(poll(&pollfd, 1, 2000), 0);
4044ad568218SChristian Brauner 	EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
4045ad568218SChristian Brauner }
4046ad568218SChristian Brauner 
4047003af8c2STerry Tritton 
get_next_fd(int prev_fd)4048003af8c2STerry Tritton int get_next_fd(int prev_fd)
4049003af8c2STerry Tritton {
4050003af8c2STerry Tritton 	for (int i = prev_fd + 1; i < FD_SETSIZE; ++i) {
4051003af8c2STerry Tritton 		if (fcntl(i, F_GETFD) == -1)
4052003af8c2STerry Tritton 			return i;
4053003af8c2STerry Tritton 	}
4054003af8c2STerry Tritton 	_exit(EXIT_FAILURE);
4055003af8c2STerry Tritton }
4056003af8c2STerry Tritton 
TEST(user_notification_addfd)4057c97aedc5SSargun Dhillon TEST(user_notification_addfd)
4058c97aedc5SSargun Dhillon {
4059c97aedc5SSargun Dhillon 	pid_t pid;
4060c97aedc5SSargun Dhillon 	long ret;
406193e720d7SKees Cook 	int status, listener, memfd, fd, nextfd;
4062c97aedc5SSargun Dhillon 	struct seccomp_notif_addfd addfd = {};
4063c97aedc5SSargun Dhillon 	struct seccomp_notif_addfd_small small = {};
4064c97aedc5SSargun Dhillon 	struct seccomp_notif_addfd_big big = {};
4065c97aedc5SSargun Dhillon 	struct seccomp_notif req = {};
4066c97aedc5SSargun Dhillon 	struct seccomp_notif_resp resp = {};
4067c97aedc5SSargun Dhillon 	/* 100 ms */
4068c97aedc5SSargun Dhillon 	struct timespec delay = { .tv_nsec = 100000000 };
4069c97aedc5SSargun Dhillon 
407093e720d7SKees Cook 	/* There may be arbitrary already-open fds at test start. */
4071c97aedc5SSargun Dhillon 	memfd = memfd_create("test", 0);
4072c97aedc5SSargun Dhillon 	ASSERT_GE(memfd, 0);
4073003af8c2STerry Tritton 	nextfd = get_next_fd(memfd);
4074c97aedc5SSargun Dhillon 
4075c97aedc5SSargun Dhillon 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
4076c97aedc5SSargun Dhillon 	ASSERT_EQ(0, ret) {
4077c97aedc5SSargun Dhillon 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
4078c97aedc5SSargun Dhillon 	}
4079c97aedc5SSargun Dhillon 
408093e720d7SKees Cook 	/* fd: 4 */
4081c97aedc5SSargun Dhillon 	/* Check that the basic notification machinery works */
4082c97aedc5SSargun Dhillon 	listener = user_notif_syscall(__NR_getppid,
4083c97aedc5SSargun Dhillon 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
4084003af8c2STerry Tritton 	ASSERT_EQ(listener, nextfd);
4085003af8c2STerry Tritton 	nextfd = get_next_fd(nextfd);
4086c97aedc5SSargun Dhillon 
4087c97aedc5SSargun Dhillon 	pid = fork();
4088c97aedc5SSargun Dhillon 	ASSERT_GE(pid, 0);
4089c97aedc5SSargun Dhillon 
4090c97aedc5SSargun Dhillon 	if (pid == 0) {
4091e540ad97SRodrigo Campos 		/* fds will be added and this value is expected */
4092c97aedc5SSargun Dhillon 		if (syscall(__NR_getppid) != USER_NOTIF_MAGIC)
4093c97aedc5SSargun Dhillon 			exit(1);
4094e540ad97SRodrigo Campos 
4095e540ad97SRodrigo Campos 		/* Atomic addfd+send is received here. Check it is a valid fd */
4096e540ad97SRodrigo Campos 		if (fcntl(syscall(__NR_getppid), F_GETFD) == -1)
4097e540ad97SRodrigo Campos 			exit(1);
4098e540ad97SRodrigo Campos 
4099c97aedc5SSargun Dhillon 		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
4100c97aedc5SSargun Dhillon 	}
4101c97aedc5SSargun Dhillon 
4102c97aedc5SSargun Dhillon 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
4103c97aedc5SSargun Dhillon 
4104c97aedc5SSargun Dhillon 	addfd.srcfd = memfd;
4105c97aedc5SSargun Dhillon 	addfd.newfd = 0;
4106c97aedc5SSargun Dhillon 	addfd.id = req.id;
4107c97aedc5SSargun Dhillon 	addfd.flags = 0x0;
4108c97aedc5SSargun Dhillon 
4109c97aedc5SSargun Dhillon 	/* Verify bad newfd_flags cannot be set */
4110c97aedc5SSargun Dhillon 	addfd.newfd_flags = ~O_CLOEXEC;
4111c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
4112c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, EINVAL);
4113c97aedc5SSargun Dhillon 	addfd.newfd_flags = O_CLOEXEC;
4114c97aedc5SSargun Dhillon 
4115c97aedc5SSargun Dhillon 	/* Verify bad flags cannot be set */
4116c97aedc5SSargun Dhillon 	addfd.flags = 0xff;
4117c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
4118c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, EINVAL);
4119c97aedc5SSargun Dhillon 	addfd.flags = 0;
4120c97aedc5SSargun Dhillon 
4121c97aedc5SSargun Dhillon 	/* Verify that remote_fd cannot be set without setting flags */
4122c97aedc5SSargun Dhillon 	addfd.newfd = 1;
4123c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
4124c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, EINVAL);
4125c97aedc5SSargun Dhillon 	addfd.newfd = 0;
4126c97aedc5SSargun Dhillon 
4127c97aedc5SSargun Dhillon 	/* Verify small size cannot be set */
4128c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_SMALL, &small), -1);
4129c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, EINVAL);
4130c97aedc5SSargun Dhillon 
4131c97aedc5SSargun Dhillon 	/* Verify we can't send bits filled in unknown buffer area */
4132c97aedc5SSargun Dhillon 	memset(&big, 0xAA, sizeof(big));
4133c97aedc5SSargun Dhillon 	big.addfd = addfd;
4134c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big), -1);
4135c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, E2BIG);
4136c97aedc5SSargun Dhillon 
4137c97aedc5SSargun Dhillon 
4138c97aedc5SSargun Dhillon 	/* Verify we can set an arbitrary remote fd */
4139c97aedc5SSargun Dhillon 	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
4140003af8c2STerry Tritton 	EXPECT_EQ(fd, nextfd);
4141003af8c2STerry Tritton 	nextfd = get_next_fd(nextfd);
4142c97aedc5SSargun Dhillon 	EXPECT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
4143c97aedc5SSargun Dhillon 
4144c97aedc5SSargun Dhillon 	/* Verify we can set an arbitrary remote fd with large size */
4145c97aedc5SSargun Dhillon 	memset(&big, 0x0, sizeof(big));
4146c97aedc5SSargun Dhillon 	big.addfd = addfd;
4147c97aedc5SSargun Dhillon 	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big);
4148003af8c2STerry Tritton 	EXPECT_EQ(fd, nextfd);
4149003af8c2STerry Tritton 	nextfd = get_next_fd(nextfd);
4150c97aedc5SSargun Dhillon 
4151c97aedc5SSargun Dhillon 	/* Verify we can set a specific remote fd */
4152c97aedc5SSargun Dhillon 	addfd.newfd = 42;
4153c97aedc5SSargun Dhillon 	addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
4154c97aedc5SSargun Dhillon 	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
4155c97aedc5SSargun Dhillon 	EXPECT_EQ(fd, 42);
4156c97aedc5SSargun Dhillon 	EXPECT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
4157c97aedc5SSargun Dhillon 
4158c97aedc5SSargun Dhillon 	/* Resume syscall */
4159c97aedc5SSargun Dhillon 	resp.id = req.id;
4160c97aedc5SSargun Dhillon 	resp.error = 0;
4161c97aedc5SSargun Dhillon 	resp.val = USER_NOTIF_MAGIC;
4162c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
4163c97aedc5SSargun Dhillon 
4164c97aedc5SSargun Dhillon 	/*
4165c97aedc5SSargun Dhillon 	 * This sets the ID of the ADD FD to the last request plus 1. The
4166c97aedc5SSargun Dhillon 	 * notification ID increments 1 per notification.
4167c97aedc5SSargun Dhillon 	 */
4168c97aedc5SSargun Dhillon 	addfd.id = req.id + 1;
4169c97aedc5SSargun Dhillon 
4170c97aedc5SSargun Dhillon 	/* This spins until the underlying notification is generated */
4171c97aedc5SSargun Dhillon 	while (ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd) != -1 &&
4172c97aedc5SSargun Dhillon 	       errno != -EINPROGRESS)
4173c97aedc5SSargun Dhillon 		nanosleep(&delay, NULL);
4174c97aedc5SSargun Dhillon 
4175c97aedc5SSargun Dhillon 	memset(&req, 0, sizeof(req));
4176c97aedc5SSargun Dhillon 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
4177c97aedc5SSargun Dhillon 	ASSERT_EQ(addfd.id, req.id);
4178c97aedc5SSargun Dhillon 
4179e540ad97SRodrigo Campos 	/* Verify we can do an atomic addfd and send */
4180e540ad97SRodrigo Campos 	addfd.newfd = 0;
4181e540ad97SRodrigo Campos 	addfd.flags = SECCOMP_ADDFD_FLAG_SEND;
4182e540ad97SRodrigo Campos 	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
418393e720d7SKees Cook 	/*
418493e720d7SKees Cook 	 * Child has earlier "low" fds and now 42, so we expect the next
418593e720d7SKees Cook 	 * lowest available fd to be assigned here.
418693e720d7SKees Cook 	 */
4187003af8c2STerry Tritton 	EXPECT_EQ(fd, nextfd);
4188003af8c2STerry Tritton 	nextfd = get_next_fd(nextfd);
418948d5fd06SKees Cook 	ASSERT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
4190e540ad97SRodrigo Campos 
4191e540ad97SRodrigo Campos 	/*
4192e540ad97SRodrigo Campos 	 * This sets the ID of the ADD FD to the last request plus 1. The
4193e540ad97SRodrigo Campos 	 * notification ID increments 1 per notification.
4194e540ad97SRodrigo Campos 	 */
4195e540ad97SRodrigo Campos 	addfd.id = req.id + 1;
4196e540ad97SRodrigo Campos 
4197e540ad97SRodrigo Campos 	/* This spins until the underlying notification is generated */
4198e540ad97SRodrigo Campos 	while (ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd) != -1 &&
4199e540ad97SRodrigo Campos 	       errno != -EINPROGRESS)
4200e540ad97SRodrigo Campos 		nanosleep(&delay, NULL);
4201e540ad97SRodrigo Campos 
4202e540ad97SRodrigo Campos 	memset(&req, 0, sizeof(req));
4203e540ad97SRodrigo Campos 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
4204e540ad97SRodrigo Campos 	ASSERT_EQ(addfd.id, req.id);
4205e540ad97SRodrigo Campos 
4206c97aedc5SSargun Dhillon 	resp.id = req.id;
4207c97aedc5SSargun Dhillon 	resp.error = 0;
4208c97aedc5SSargun Dhillon 	resp.val = USER_NOTIF_MAGIC;
4209c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
4210c97aedc5SSargun Dhillon 
4211c97aedc5SSargun Dhillon 	/* Wait for child to finish. */
4212c97aedc5SSargun Dhillon 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
4213c97aedc5SSargun Dhillon 	EXPECT_EQ(true, WIFEXITED(status));
4214c97aedc5SSargun Dhillon 	EXPECT_EQ(0, WEXITSTATUS(status));
4215c97aedc5SSargun Dhillon 
4216c97aedc5SSargun Dhillon 	close(memfd);
4217c97aedc5SSargun Dhillon }
4218c97aedc5SSargun Dhillon 
TEST(user_notification_addfd_rlimit)4219c97aedc5SSargun Dhillon TEST(user_notification_addfd_rlimit)
4220c97aedc5SSargun Dhillon {
4221c97aedc5SSargun Dhillon 	pid_t pid;
4222c97aedc5SSargun Dhillon 	long ret;
4223c97aedc5SSargun Dhillon 	int status, listener, memfd;
4224c97aedc5SSargun Dhillon 	struct seccomp_notif_addfd addfd = {};
4225c97aedc5SSargun Dhillon 	struct seccomp_notif req = {};
4226c97aedc5SSargun Dhillon 	struct seccomp_notif_resp resp = {};
4227c97aedc5SSargun Dhillon 	const struct rlimit lim = {
4228c97aedc5SSargun Dhillon 		.rlim_cur	= 0,
4229c97aedc5SSargun Dhillon 		.rlim_max	= 0,
4230c97aedc5SSargun Dhillon 	};
4231c97aedc5SSargun Dhillon 
4232c97aedc5SSargun Dhillon 	memfd = memfd_create("test", 0);
4233c97aedc5SSargun Dhillon 	ASSERT_GE(memfd, 0);
4234c97aedc5SSargun Dhillon 
4235c97aedc5SSargun Dhillon 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
4236c97aedc5SSargun Dhillon 	ASSERT_EQ(0, ret) {
4237c97aedc5SSargun Dhillon 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
4238c97aedc5SSargun Dhillon 	}
4239c97aedc5SSargun Dhillon 
4240c97aedc5SSargun Dhillon 	/* Check that the basic notification machinery works */
4241c97aedc5SSargun Dhillon 	listener = user_notif_syscall(__NR_getppid,
4242c97aedc5SSargun Dhillon 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
4243c97aedc5SSargun Dhillon 	ASSERT_GE(listener, 0);
4244c97aedc5SSargun Dhillon 
4245c97aedc5SSargun Dhillon 	pid = fork();
4246c97aedc5SSargun Dhillon 	ASSERT_GE(pid, 0);
4247c97aedc5SSargun Dhillon 
4248c97aedc5SSargun Dhillon 	if (pid == 0)
4249c97aedc5SSargun Dhillon 		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
4250c97aedc5SSargun Dhillon 
4251c97aedc5SSargun Dhillon 
4252c97aedc5SSargun Dhillon 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
4253c97aedc5SSargun Dhillon 
4254c97aedc5SSargun Dhillon 	ASSERT_EQ(prlimit(pid, RLIMIT_NOFILE, &lim, NULL), 0);
4255c97aedc5SSargun Dhillon 
4256c97aedc5SSargun Dhillon 	addfd.srcfd = memfd;
4257c97aedc5SSargun Dhillon 	addfd.newfd_flags = O_CLOEXEC;
4258c97aedc5SSargun Dhillon 	addfd.newfd = 0;
4259c97aedc5SSargun Dhillon 	addfd.id = req.id;
4260c97aedc5SSargun Dhillon 	addfd.flags = 0;
4261c97aedc5SSargun Dhillon 
4262c97aedc5SSargun Dhillon 	/* Should probably spot check /proc/sys/fs/file-nr */
4263c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
4264c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, EMFILE);
4265c97aedc5SSargun Dhillon 
4266e540ad97SRodrigo Campos 	addfd.flags = SECCOMP_ADDFD_FLAG_SEND;
4267e540ad97SRodrigo Campos 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
4268e540ad97SRodrigo Campos 	EXPECT_EQ(errno, EMFILE);
4269e540ad97SRodrigo Campos 
4270c97aedc5SSargun Dhillon 	addfd.newfd = 100;
4271c97aedc5SSargun Dhillon 	addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
4272c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
4273c97aedc5SSargun Dhillon 	EXPECT_EQ(errno, EBADF);
4274c97aedc5SSargun Dhillon 
4275c97aedc5SSargun Dhillon 	resp.id = req.id;
4276c97aedc5SSargun Dhillon 	resp.error = 0;
4277c97aedc5SSargun Dhillon 	resp.val = USER_NOTIF_MAGIC;
4278c97aedc5SSargun Dhillon 
4279c97aedc5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
4280c97aedc5SSargun Dhillon 
4281c97aedc5SSargun Dhillon 	/* Wait for child to finish. */
4282c97aedc5SSargun Dhillon 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
4283c97aedc5SSargun Dhillon 	EXPECT_EQ(true, WIFEXITED(status));
4284c97aedc5SSargun Dhillon 	EXPECT_EQ(0, WEXITSTATUS(status));
4285c97aedc5SSargun Dhillon 
4286c97aedc5SSargun Dhillon 	close(memfd);
4287c97aedc5SSargun Dhillon }
4288c97aedc5SSargun Dhillon 
42898feae5adSAndrei Vagin #ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP
42908feae5adSAndrei Vagin #define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0)
42918feae5adSAndrei Vagin #define SECCOMP_IOCTL_NOTIF_SET_FLAGS  SECCOMP_IOW(4, __u64)
42928feae5adSAndrei Vagin #endif
42938feae5adSAndrei Vagin 
TEST(user_notification_sync)42948feae5adSAndrei Vagin TEST(user_notification_sync)
42958feae5adSAndrei Vagin {
42968feae5adSAndrei Vagin 	struct seccomp_notif req = {};
42978feae5adSAndrei Vagin 	struct seccomp_notif_resp resp = {};
42988feae5adSAndrei Vagin 	int status, listener;
42998feae5adSAndrei Vagin 	pid_t pid;
43008feae5adSAndrei Vagin 	long ret;
43018feae5adSAndrei Vagin 
43028feae5adSAndrei Vagin 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
43038feae5adSAndrei Vagin 	ASSERT_EQ(0, ret) {
43048feae5adSAndrei Vagin 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
43058feae5adSAndrei Vagin 	}
43068feae5adSAndrei Vagin 
43078feae5adSAndrei Vagin 	listener = user_notif_syscall(__NR_getppid,
43088feae5adSAndrei Vagin 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
43098feae5adSAndrei Vagin 	ASSERT_GE(listener, 0);
43108feae5adSAndrei Vagin 
43118feae5adSAndrei Vagin 	/* Try to set invalid flags. */
43128feae5adSAndrei Vagin 	EXPECT_SYSCALL_RETURN(-EINVAL,
43138feae5adSAndrei Vagin 		ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS, 0xffffffff, 0));
43148feae5adSAndrei Vagin 
43158feae5adSAndrei Vagin 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS,
43168feae5adSAndrei Vagin 			SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP, 0), 0);
43178feae5adSAndrei Vagin 
43188feae5adSAndrei Vagin 	pid = fork();
43198feae5adSAndrei Vagin 	ASSERT_GE(pid, 0);
43208feae5adSAndrei Vagin 	if (pid == 0) {
43218feae5adSAndrei Vagin 		ret = syscall(__NR_getppid);
43228feae5adSAndrei Vagin 		ASSERT_EQ(ret, USER_NOTIF_MAGIC) {
43238feae5adSAndrei Vagin 			_exit(1);
43248feae5adSAndrei Vagin 		}
43258feae5adSAndrei Vagin 		_exit(0);
43268feae5adSAndrei Vagin 	}
43278feae5adSAndrei Vagin 
43288feae5adSAndrei Vagin 	req.pid = 0;
43298feae5adSAndrei Vagin 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
43308feae5adSAndrei Vagin 
43318feae5adSAndrei Vagin 	ASSERT_EQ(req.data.nr,  __NR_getppid);
43328feae5adSAndrei Vagin 
43338feae5adSAndrei Vagin 	resp.id = req.id;
43348feae5adSAndrei Vagin 	resp.error = 0;
43358feae5adSAndrei Vagin 	resp.val = USER_NOTIF_MAGIC;
43368feae5adSAndrei Vagin 	resp.flags = 0;
43378feae5adSAndrei Vagin 	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
43388feae5adSAndrei Vagin 
43398feae5adSAndrei Vagin 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
43408feae5adSAndrei Vagin 	ASSERT_EQ(status, 0);
43418feae5adSAndrei Vagin }
43428feae5adSAndrei Vagin 
43438feae5adSAndrei Vagin 
4344d250a3e4SJann Horn /* Make sure PTRACE_O_SUSPEND_SECCOMP requires CAP_SYS_ADMIN. */
FIXTURE(O_SUSPEND_SECCOMP)4345d250a3e4SJann Horn FIXTURE(O_SUSPEND_SECCOMP) {
4346d250a3e4SJann Horn 	pid_t pid;
4347d250a3e4SJann Horn };
4348d250a3e4SJann Horn 
FIXTURE_SETUP(O_SUSPEND_SECCOMP)4349d250a3e4SJann Horn FIXTURE_SETUP(O_SUSPEND_SECCOMP)
4350d250a3e4SJann Horn {
4351d250a3e4SJann Horn 	ERRNO_FILTER(block_read, E2BIG);
4352d250a3e4SJann Horn 	cap_value_t cap_list[] = { CAP_SYS_ADMIN };
4353d250a3e4SJann Horn 	cap_t caps;
4354d250a3e4SJann Horn 
4355d250a3e4SJann Horn 	self->pid = 0;
4356d250a3e4SJann Horn 
4357d250a3e4SJann Horn 	/* make sure we don't have CAP_SYS_ADMIN */
4358d250a3e4SJann Horn 	caps = cap_get_proc();
4359d250a3e4SJann Horn 	ASSERT_NE(NULL, caps);
4360d250a3e4SJann Horn 	ASSERT_EQ(0, cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_CLEAR));
4361d250a3e4SJann Horn 	ASSERT_EQ(0, cap_set_proc(caps));
4362d250a3e4SJann Horn 	cap_free(caps);
4363d250a3e4SJann Horn 
4364d250a3e4SJann Horn 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
4365d250a3e4SJann Horn 	ASSERT_EQ(0, prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_block_read));
4366d250a3e4SJann Horn 
4367d250a3e4SJann Horn 	self->pid = fork();
4368d250a3e4SJann Horn 	ASSERT_GE(self->pid, 0);
4369d250a3e4SJann Horn 
4370d250a3e4SJann Horn 	if (self->pid == 0) {
4371d250a3e4SJann Horn 		while (1)
4372d250a3e4SJann Horn 			pause();
4373d250a3e4SJann Horn 		_exit(127);
4374d250a3e4SJann Horn 	}
4375d250a3e4SJann Horn }
4376d250a3e4SJann Horn 
FIXTURE_TEARDOWN(O_SUSPEND_SECCOMP)4377d250a3e4SJann Horn FIXTURE_TEARDOWN(O_SUSPEND_SECCOMP)
4378d250a3e4SJann Horn {
4379d250a3e4SJann Horn 	if (self->pid)
4380d250a3e4SJann Horn 		kill(self->pid, SIGKILL);
4381d250a3e4SJann Horn }
4382d250a3e4SJann Horn 
TEST_F(O_SUSPEND_SECCOMP,setoptions)4383d250a3e4SJann Horn TEST_F(O_SUSPEND_SECCOMP, setoptions)
4384d250a3e4SJann Horn {
4385d250a3e4SJann Horn 	int wstatus;
4386d250a3e4SJann Horn 
4387d250a3e4SJann Horn 	ASSERT_EQ(0, ptrace(PTRACE_ATTACH, self->pid, NULL, 0));
4388d250a3e4SJann Horn 	ASSERT_EQ(self->pid, wait(&wstatus));
4389d250a3e4SJann Horn 	ASSERT_EQ(-1, ptrace(PTRACE_SETOPTIONS, self->pid, NULL, PTRACE_O_SUSPEND_SECCOMP));
4390d250a3e4SJann Horn 	if (errno == EINVAL)
4391d250a3e4SJann Horn 		SKIP(return, "Kernel does not support PTRACE_O_SUSPEND_SECCOMP (missing CONFIG_CHECKPOINT_RESTORE?)");
4392d250a3e4SJann Horn 	ASSERT_EQ(EPERM, errno);
4393d250a3e4SJann Horn }
4394d250a3e4SJann Horn 
TEST_F(O_SUSPEND_SECCOMP,seize)4395d250a3e4SJann Horn TEST_F(O_SUSPEND_SECCOMP, seize)
4396d250a3e4SJann Horn {
4397d250a3e4SJann Horn 	int ret;
4398d250a3e4SJann Horn 
4399d250a3e4SJann Horn 	ret = ptrace(PTRACE_SEIZE, self->pid, NULL, PTRACE_O_SUSPEND_SECCOMP);
4400d250a3e4SJann Horn 	ASSERT_EQ(-1, ret);
4401d250a3e4SJann Horn 	if (errno == EINVAL)
4402d250a3e4SJann Horn 		SKIP(return, "Kernel does not support PTRACE_O_SUSPEND_SECCOMP (missing CONFIG_CHECKPOINT_RESTORE?)");
4403d250a3e4SJann Horn 	ASSERT_EQ(EPERM, errno);
4404d250a3e4SJann Horn }
4405d250a3e4SJann Horn 
4406922a1b52SSargun Dhillon /*
4407922a1b52SSargun Dhillon  * get_nth - Get the nth, space separated entry in a file.
4408922a1b52SSargun Dhillon  *
4409922a1b52SSargun Dhillon  * Returns the length of the read field.
4410922a1b52SSargun Dhillon  * Throws error if field is zero-lengthed.
4411922a1b52SSargun Dhillon  */
get_nth(struct __test_metadata * _metadata,const char * path,const unsigned int position,char ** entry)4412922a1b52SSargun Dhillon static ssize_t get_nth(struct __test_metadata *_metadata, const char *path,
4413922a1b52SSargun Dhillon 		     const unsigned int position, char **entry)
4414922a1b52SSargun Dhillon {
4415922a1b52SSargun Dhillon 	char *line = NULL;
4416922a1b52SSargun Dhillon 	unsigned int i;
4417922a1b52SSargun Dhillon 	ssize_t nread;
4418922a1b52SSargun Dhillon 	size_t len = 0;
4419922a1b52SSargun Dhillon 	FILE *f;
4420922a1b52SSargun Dhillon 
4421922a1b52SSargun Dhillon 	f = fopen(path, "r");
4422922a1b52SSargun Dhillon 	ASSERT_NE(f, NULL) {
44235e91d2a4SColin Ian King 		TH_LOG("Could not open %s: %s", path, strerror(errno));
4424922a1b52SSargun Dhillon 	}
4425922a1b52SSargun Dhillon 
4426922a1b52SSargun Dhillon 	for (i = 0; i < position; i++) {
4427922a1b52SSargun Dhillon 		nread = getdelim(&line, &len, ' ', f);
4428922a1b52SSargun Dhillon 		ASSERT_GE(nread, 0) {
4429922a1b52SSargun Dhillon 			TH_LOG("Failed to read %d entry in file %s", i, path);
4430922a1b52SSargun Dhillon 		}
4431922a1b52SSargun Dhillon 	}
4432922a1b52SSargun Dhillon 	fclose(f);
4433922a1b52SSargun Dhillon 
4434922a1b52SSargun Dhillon 	ASSERT_GT(nread, 0) {
4435922a1b52SSargun Dhillon 		TH_LOG("Entry in file %s had zero length", path);
4436922a1b52SSargun Dhillon 	}
4437922a1b52SSargun Dhillon 
4438922a1b52SSargun Dhillon 	*entry = line;
4439922a1b52SSargun Dhillon 	return nread - 1;
4440922a1b52SSargun Dhillon }
4441922a1b52SSargun Dhillon 
4442922a1b52SSargun Dhillon /* For a given PID, get the task state (D, R, etc...) */
get_proc_stat(struct __test_metadata * _metadata,pid_t pid)4443922a1b52SSargun Dhillon static char get_proc_stat(struct __test_metadata *_metadata, pid_t pid)
4444662340efSSargun Dhillon {
4445662340efSSargun Dhillon 	char proc_path[100] = {0};
4446662340efSSargun Dhillon 	char status;
4447922a1b52SSargun Dhillon 	char *line;
4448662340efSSargun Dhillon 
4449662340efSSargun Dhillon 	snprintf(proc_path, sizeof(proc_path), "/proc/%d/stat", pid);
4450922a1b52SSargun Dhillon 	ASSERT_EQ(get_nth(_metadata, proc_path, 3, &line), 1);
4451662340efSSargun Dhillon 
4452662340efSSargun Dhillon 	status = *line;
4453662340efSSargun Dhillon 	free(line);
4454662340efSSargun Dhillon 
4455662340efSSargun Dhillon 	return status;
4456662340efSSargun Dhillon }
4457662340efSSargun Dhillon 
TEST(user_notification_fifo)4458662340efSSargun Dhillon TEST(user_notification_fifo)
4459662340efSSargun Dhillon {
4460662340efSSargun Dhillon 	struct seccomp_notif_resp resp = {};
4461662340efSSargun Dhillon 	struct seccomp_notif req = {};
4462662340efSSargun Dhillon 	int i, status, listener;
4463662340efSSargun Dhillon 	pid_t pid, pids[3];
4464662340efSSargun Dhillon 	__u64 baseid;
4465662340efSSargun Dhillon 	long ret;
4466662340efSSargun Dhillon 	/* 100 ms */
4467662340efSSargun Dhillon 	struct timespec delay = { .tv_nsec = 100000000 };
4468662340efSSargun Dhillon 
4469662340efSSargun Dhillon 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
4470662340efSSargun Dhillon 	ASSERT_EQ(0, ret) {
4471662340efSSargun Dhillon 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
4472662340efSSargun Dhillon 	}
4473662340efSSargun Dhillon 
4474662340efSSargun Dhillon 	/* Setup a listener */
4475662340efSSargun Dhillon 	listener = user_notif_syscall(__NR_getppid,
4476662340efSSargun Dhillon 				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
4477662340efSSargun Dhillon 	ASSERT_GE(listener, 0);
4478662340efSSargun Dhillon 
4479662340efSSargun Dhillon 	pid = fork();
4480662340efSSargun Dhillon 	ASSERT_GE(pid, 0);
4481662340efSSargun Dhillon 
4482662340efSSargun Dhillon 	if (pid == 0) {
4483662340efSSargun Dhillon 		ret = syscall(__NR_getppid);
4484662340efSSargun Dhillon 		exit(ret != USER_NOTIF_MAGIC);
4485662340efSSargun Dhillon 	}
4486662340efSSargun Dhillon 
4487662340efSSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
4488662340efSSargun Dhillon 	baseid = req.id + 1;
4489662340efSSargun Dhillon 
4490662340efSSargun Dhillon 	resp.id = req.id;
4491662340efSSargun Dhillon 	resp.error = 0;
4492662340efSSargun Dhillon 	resp.val = USER_NOTIF_MAGIC;
4493662340efSSargun Dhillon 
4494662340efSSargun Dhillon 	/* check that we make sure flags == 0 */
4495662340efSSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
4496662340efSSargun Dhillon 
4497662340efSSargun Dhillon 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
4498662340efSSargun Dhillon 	EXPECT_EQ(true, WIFEXITED(status));
4499662340efSSargun Dhillon 	EXPECT_EQ(0, WEXITSTATUS(status));
4500662340efSSargun Dhillon 
4501662340efSSargun Dhillon 	/* Start children, and generate notifications */
4502662340efSSargun Dhillon 	for (i = 0; i < ARRAY_SIZE(pids); i++) {
4503662340efSSargun Dhillon 		pid = fork();
4504662340efSSargun Dhillon 		if (pid == 0) {
4505662340efSSargun Dhillon 			ret = syscall(__NR_getppid);
4506662340efSSargun Dhillon 			exit(ret != USER_NOTIF_MAGIC);
4507662340efSSargun Dhillon 		}
4508662340efSSargun Dhillon 		pids[i] = pid;
4509662340efSSargun Dhillon 	}
4510662340efSSargun Dhillon 
4511662340efSSargun Dhillon 	/* This spins until all of the children are sleeping */
4512662340efSSargun Dhillon restart_wait:
4513662340efSSargun Dhillon 	for (i = 0; i < ARRAY_SIZE(pids); i++) {
4514922a1b52SSargun Dhillon 		if (get_proc_stat(_metadata, pids[i]) != 'S') {
4515662340efSSargun Dhillon 			nanosleep(&delay, NULL);
4516662340efSSargun Dhillon 			goto restart_wait;
4517662340efSSargun Dhillon 		}
4518662340efSSargun Dhillon 	}
4519662340efSSargun Dhillon 
4520662340efSSargun Dhillon 	/* Read the notifications in order (and respond) */
4521662340efSSargun Dhillon 	for (i = 0; i < ARRAY_SIZE(pids); i++) {
4522662340efSSargun Dhillon 		memset(&req, 0, sizeof(req));
4523662340efSSargun Dhillon 		EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
4524662340efSSargun Dhillon 		EXPECT_EQ(req.id, baseid + i);
4525662340efSSargun Dhillon 		resp.id = req.id;
4526662340efSSargun Dhillon 		EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
4527662340efSSargun Dhillon 	}
4528662340efSSargun Dhillon 
4529662340efSSargun Dhillon 	/* Make sure notifications were received */
4530662340efSSargun Dhillon 	for (i = 0; i < ARRAY_SIZE(pids); i++) {
4531662340efSSargun Dhillon 		EXPECT_EQ(waitpid(pids[i], &status, 0), pids[i]);
4532662340efSSargun Dhillon 		EXPECT_EQ(true, WIFEXITED(status));
4533662340efSSargun Dhillon 		EXPECT_EQ(0, WEXITSTATUS(status));
4534662340efSSargun Dhillon 	}
4535662340efSSargun Dhillon }
4536662340efSSargun Dhillon 
45373b96a9c5SSargun Dhillon /* get_proc_syscall - Get the syscall in progress for a given pid
45383b96a9c5SSargun Dhillon  *
45393b96a9c5SSargun Dhillon  * Returns the current syscall number for a given process
45403b96a9c5SSargun Dhillon  * Returns -1 if not in syscall (running or blocked)
45413b96a9c5SSargun Dhillon  */
get_proc_syscall(struct __test_metadata * _metadata,int pid)45423b96a9c5SSargun Dhillon static long get_proc_syscall(struct __test_metadata *_metadata, int pid)
45433b96a9c5SSargun Dhillon {
45443b96a9c5SSargun Dhillon 	char proc_path[100] = {0};
45453b96a9c5SSargun Dhillon 	long ret = -1;
45463b96a9c5SSargun Dhillon 	ssize_t nread;
45473b96a9c5SSargun Dhillon 	char *line;
45483b96a9c5SSargun Dhillon 
45493b96a9c5SSargun Dhillon 	snprintf(proc_path, sizeof(proc_path), "/proc/%d/syscall", pid);
45503b96a9c5SSargun Dhillon 	nread = get_nth(_metadata, proc_path, 1, &line);
45513b96a9c5SSargun Dhillon 	ASSERT_GT(nread, 0);
45523b96a9c5SSargun Dhillon 
45533b96a9c5SSargun Dhillon 	if (!strncmp("running", line, MIN(7, nread)))
45543b96a9c5SSargun Dhillon 		ret = strtol(line, NULL, 16);
45553b96a9c5SSargun Dhillon 
45563b96a9c5SSargun Dhillon 	free(line);
45573b96a9c5SSargun Dhillon 	return ret;
45583b96a9c5SSargun Dhillon }
45593b96a9c5SSargun Dhillon 
45603b96a9c5SSargun Dhillon /* Ensure non-fatal signals prior to receive are unmodified */
TEST(user_notification_wait_killable_pre_notification)45613b96a9c5SSargun Dhillon TEST(user_notification_wait_killable_pre_notification)
45623b96a9c5SSargun Dhillon {
45633b96a9c5SSargun Dhillon 	struct sigaction new_action = {
45643b96a9c5SSargun Dhillon 		.sa_handler = signal_handler,
45653b96a9c5SSargun Dhillon 	};
45663b96a9c5SSargun Dhillon 	int listener, status, sk_pair[2];
45673b96a9c5SSargun Dhillon 	pid_t pid;
45683b96a9c5SSargun Dhillon 	long ret;
45693b96a9c5SSargun Dhillon 	char c;
45703b96a9c5SSargun Dhillon 	/* 100 ms */
45713b96a9c5SSargun Dhillon 	struct timespec delay = { .tv_nsec = 100000000 };
45723b96a9c5SSargun Dhillon 
45733b96a9c5SSargun Dhillon 	ASSERT_EQ(sigemptyset(&new_action.sa_mask), 0);
45743b96a9c5SSargun Dhillon 
45753b96a9c5SSargun Dhillon 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
45763b96a9c5SSargun Dhillon 	ASSERT_EQ(0, ret)
45773b96a9c5SSargun Dhillon 	{
45783b96a9c5SSargun Dhillon 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
45793b96a9c5SSargun Dhillon 	}
45803b96a9c5SSargun Dhillon 
45813b96a9c5SSargun Dhillon 	ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
45823b96a9c5SSargun Dhillon 
45833b96a9c5SSargun Dhillon 	listener = user_notif_syscall(
45843b96a9c5SSargun Dhillon 		__NR_getppid, SECCOMP_FILTER_FLAG_NEW_LISTENER |
45853b96a9c5SSargun Dhillon 				      SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV);
45863b96a9c5SSargun Dhillon 	ASSERT_GE(listener, 0);
45873b96a9c5SSargun Dhillon 
45883b96a9c5SSargun Dhillon 	/*
45893b96a9c5SSargun Dhillon 	 * Check that we can kill the process with SIGUSR1 prior to receiving
45903b96a9c5SSargun Dhillon 	 * the notification. SIGUSR1 is wired up to a custom signal handler,
45913b96a9c5SSargun Dhillon 	 * and make sure it gets called.
45923b96a9c5SSargun Dhillon 	 */
45933b96a9c5SSargun Dhillon 	pid = fork();
45943b96a9c5SSargun Dhillon 	ASSERT_GE(pid, 0);
45953b96a9c5SSargun Dhillon 
45963b96a9c5SSargun Dhillon 	if (pid == 0) {
45973b96a9c5SSargun Dhillon 		close(sk_pair[0]);
45983b96a9c5SSargun Dhillon 		handled = sk_pair[1];
45993b96a9c5SSargun Dhillon 
46003b96a9c5SSargun Dhillon 		/* Setup the non-fatal sigaction without SA_RESTART */
46013b96a9c5SSargun Dhillon 		if (sigaction(SIGUSR1, &new_action, NULL)) {
46023b96a9c5SSargun Dhillon 			perror("sigaction");
46033b96a9c5SSargun Dhillon 			exit(1);
46043b96a9c5SSargun Dhillon 		}
46053b96a9c5SSargun Dhillon 
46063b96a9c5SSargun Dhillon 		ret = syscall(__NR_getppid);
46073b96a9c5SSargun Dhillon 		/* Make sure we got a return from a signal interruption */
46083b96a9c5SSargun Dhillon 		exit(ret != -1 || errno != EINTR);
46093b96a9c5SSargun Dhillon 	}
46103b96a9c5SSargun Dhillon 
46113b96a9c5SSargun Dhillon 	/*
46123b96a9c5SSargun Dhillon 	 * Make sure we've gotten to the seccomp user notification wait
46133b96a9c5SSargun Dhillon 	 * from getppid prior to sending any signals
46143b96a9c5SSargun Dhillon 	 */
46153b96a9c5SSargun Dhillon 	while (get_proc_syscall(_metadata, pid) != __NR_getppid &&
46163b96a9c5SSargun Dhillon 	       get_proc_stat(_metadata, pid) != 'S')
46173b96a9c5SSargun Dhillon 		nanosleep(&delay, NULL);
46183b96a9c5SSargun Dhillon 
46193b96a9c5SSargun Dhillon 	/* Send non-fatal kill signal */
46203b96a9c5SSargun Dhillon 	EXPECT_EQ(kill(pid, SIGUSR1), 0);
46213b96a9c5SSargun Dhillon 
46223b96a9c5SSargun Dhillon 	/* wait for process to exit (exit checks for EINTR) */
46233b96a9c5SSargun Dhillon 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
46243b96a9c5SSargun Dhillon 	EXPECT_EQ(true, WIFEXITED(status));
46253b96a9c5SSargun Dhillon 	EXPECT_EQ(0, WEXITSTATUS(status));
46263b96a9c5SSargun Dhillon 
46273b96a9c5SSargun Dhillon 	EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
46283b96a9c5SSargun Dhillon }
46293b96a9c5SSargun Dhillon 
46303b96a9c5SSargun Dhillon /* Ensure non-fatal signals after receive are blocked */
TEST(user_notification_wait_killable)46313b96a9c5SSargun Dhillon TEST(user_notification_wait_killable)
46323b96a9c5SSargun Dhillon {
46333b96a9c5SSargun Dhillon 	struct sigaction new_action = {
46343b96a9c5SSargun Dhillon 		.sa_handler = signal_handler,
46353b96a9c5SSargun Dhillon 	};
46363b96a9c5SSargun Dhillon 	struct seccomp_notif_resp resp = {};
46373b96a9c5SSargun Dhillon 	struct seccomp_notif req = {};
46383b96a9c5SSargun Dhillon 	int listener, status, sk_pair[2];
46393b96a9c5SSargun Dhillon 	pid_t pid;
46403b96a9c5SSargun Dhillon 	long ret;
46413b96a9c5SSargun Dhillon 	char c;
46423b96a9c5SSargun Dhillon 	/* 100 ms */
46433b96a9c5SSargun Dhillon 	struct timespec delay = { .tv_nsec = 100000000 };
46443b96a9c5SSargun Dhillon 
46453b96a9c5SSargun Dhillon 	ASSERT_EQ(sigemptyset(&new_action.sa_mask), 0);
46463b96a9c5SSargun Dhillon 
46473b96a9c5SSargun Dhillon 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
46483b96a9c5SSargun Dhillon 	ASSERT_EQ(0, ret)
46493b96a9c5SSargun Dhillon 	{
46503b96a9c5SSargun Dhillon 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
46513b96a9c5SSargun Dhillon 	}
46523b96a9c5SSargun Dhillon 
46533b96a9c5SSargun Dhillon 	ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
46543b96a9c5SSargun Dhillon 
46553b96a9c5SSargun Dhillon 	listener = user_notif_syscall(
46563b96a9c5SSargun Dhillon 		__NR_getppid, SECCOMP_FILTER_FLAG_NEW_LISTENER |
46573b96a9c5SSargun Dhillon 				      SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV);
46583b96a9c5SSargun Dhillon 	ASSERT_GE(listener, 0);
46593b96a9c5SSargun Dhillon 
46603b96a9c5SSargun Dhillon 	pid = fork();
46613b96a9c5SSargun Dhillon 	ASSERT_GE(pid, 0);
46623b96a9c5SSargun Dhillon 
46633b96a9c5SSargun Dhillon 	if (pid == 0) {
46643b96a9c5SSargun Dhillon 		close(sk_pair[0]);
46653b96a9c5SSargun Dhillon 		handled = sk_pair[1];
46663b96a9c5SSargun Dhillon 
46673b96a9c5SSargun Dhillon 		/* Setup the sigaction without SA_RESTART */
46683b96a9c5SSargun Dhillon 		if (sigaction(SIGUSR1, &new_action, NULL)) {
46693b96a9c5SSargun Dhillon 			perror("sigaction");
46703b96a9c5SSargun Dhillon 			exit(1);
46713b96a9c5SSargun Dhillon 		}
46723b96a9c5SSargun Dhillon 
46733b96a9c5SSargun Dhillon 		/* Make sure that the syscall is completed (no EINTR) */
46743b96a9c5SSargun Dhillon 		ret = syscall(__NR_getppid);
46753b96a9c5SSargun Dhillon 		exit(ret != USER_NOTIF_MAGIC);
46763b96a9c5SSargun Dhillon 	}
46773b96a9c5SSargun Dhillon 
46783b96a9c5SSargun Dhillon 	/*
46793b96a9c5SSargun Dhillon 	 * Get the notification, to make move the notifying process into a
46803b96a9c5SSargun Dhillon 	 * non-preemptible (TASK_KILLABLE) state.
46813b96a9c5SSargun Dhillon 	 */
46823b96a9c5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
46833b96a9c5SSargun Dhillon 	/* Send non-fatal kill signal */
46843b96a9c5SSargun Dhillon 	EXPECT_EQ(kill(pid, SIGUSR1), 0);
46853b96a9c5SSargun Dhillon 
46863b96a9c5SSargun Dhillon 	/*
46873b96a9c5SSargun Dhillon 	 * Make sure the task enters moves to TASK_KILLABLE by waiting for
46883b96a9c5SSargun Dhillon 	 * D (Disk Sleep) state after receiving non-fatal signal.
46893b96a9c5SSargun Dhillon 	 */
46903b96a9c5SSargun Dhillon 	while (get_proc_stat(_metadata, pid) != 'D')
46913b96a9c5SSargun Dhillon 		nanosleep(&delay, NULL);
46923b96a9c5SSargun Dhillon 
46933b96a9c5SSargun Dhillon 	resp.id = req.id;
46943b96a9c5SSargun Dhillon 	resp.val = USER_NOTIF_MAGIC;
46953b96a9c5SSargun Dhillon 	/* Make sure the notification is found and able to be replied to */
46963b96a9c5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
46973b96a9c5SSargun Dhillon 
46983b96a9c5SSargun Dhillon 	/*
46993b96a9c5SSargun Dhillon 	 * Make sure that the signal handler does get called once we're back in
47003b96a9c5SSargun Dhillon 	 * userspace.
47013b96a9c5SSargun Dhillon 	 */
47023b96a9c5SSargun Dhillon 	EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
47033b96a9c5SSargun Dhillon 	/* wait for process to exit (exit checks for USER_NOTIF_MAGIC) */
47043b96a9c5SSargun Dhillon 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
47053b96a9c5SSargun Dhillon 	EXPECT_EQ(true, WIFEXITED(status));
47063b96a9c5SSargun Dhillon 	EXPECT_EQ(0, WEXITSTATUS(status));
47073b96a9c5SSargun Dhillon }
47083b96a9c5SSargun Dhillon 
47093b96a9c5SSargun Dhillon /* Ensure fatal signals after receive are not blocked */
TEST(user_notification_wait_killable_fatal)47103b96a9c5SSargun Dhillon TEST(user_notification_wait_killable_fatal)
47113b96a9c5SSargun Dhillon {
47123b96a9c5SSargun Dhillon 	struct seccomp_notif req = {};
47133b96a9c5SSargun Dhillon 	int listener, status;
47143b96a9c5SSargun Dhillon 	pid_t pid;
47153b96a9c5SSargun Dhillon 	long ret;
47163b96a9c5SSargun Dhillon 	/* 100 ms */
47173b96a9c5SSargun Dhillon 	struct timespec delay = { .tv_nsec = 100000000 };
47183b96a9c5SSargun Dhillon 
47193b96a9c5SSargun Dhillon 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
47203b96a9c5SSargun Dhillon 	ASSERT_EQ(0, ret)
47213b96a9c5SSargun Dhillon 	{
47223b96a9c5SSargun Dhillon 		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
47233b96a9c5SSargun Dhillon 	}
47243b96a9c5SSargun Dhillon 
47253b96a9c5SSargun Dhillon 	listener = user_notif_syscall(
47263b96a9c5SSargun Dhillon 		__NR_getppid, SECCOMP_FILTER_FLAG_NEW_LISTENER |
47273b96a9c5SSargun Dhillon 				      SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV);
47283b96a9c5SSargun Dhillon 	ASSERT_GE(listener, 0);
47293b96a9c5SSargun Dhillon 
47303b96a9c5SSargun Dhillon 	pid = fork();
47313b96a9c5SSargun Dhillon 	ASSERT_GE(pid, 0);
47323b96a9c5SSargun Dhillon 
47333b96a9c5SSargun Dhillon 	if (pid == 0) {
47343b96a9c5SSargun Dhillon 		/* This should never complete as it should get a SIGTERM */
47353b96a9c5SSargun Dhillon 		syscall(__NR_getppid);
47363b96a9c5SSargun Dhillon 		exit(1);
47373b96a9c5SSargun Dhillon 	}
47383b96a9c5SSargun Dhillon 
47393b96a9c5SSargun Dhillon 	while (get_proc_stat(_metadata, pid) != 'S')
47403b96a9c5SSargun Dhillon 		nanosleep(&delay, NULL);
47413b96a9c5SSargun Dhillon 
47423b96a9c5SSargun Dhillon 	/*
47433b96a9c5SSargun Dhillon 	 * Get the notification, to make move the notifying process into a
47443b96a9c5SSargun Dhillon 	 * non-preemptible (TASK_KILLABLE) state.
47453b96a9c5SSargun Dhillon 	 */
47463b96a9c5SSargun Dhillon 	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
47473b96a9c5SSargun Dhillon 	/* Kill the process with a fatal signal */
47483b96a9c5SSargun Dhillon 	EXPECT_EQ(kill(pid, SIGTERM), 0);
47493b96a9c5SSargun Dhillon 
47503b96a9c5SSargun Dhillon 	/*
47513b96a9c5SSargun Dhillon 	 * Wait for the process to exit, and make sure the process terminated
47523b96a9c5SSargun Dhillon 	 * due to the SIGTERM signal.
47533b96a9c5SSargun Dhillon 	 */
47543b96a9c5SSargun Dhillon 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
47553b96a9c5SSargun Dhillon 	EXPECT_EQ(true, WIFSIGNALED(status));
47563b96a9c5SSargun Dhillon 	EXPECT_EQ(SIGTERM, WTERMSIG(status));
47573b96a9c5SSargun Dhillon }
47583b96a9c5SSargun Dhillon 
4759c99ee51aSKees Cook /*
4760c99ee51aSKees Cook  * TODO:
4761c99ee51aSKees Cook  * - expand NNP testing
4762c99ee51aSKees Cook  * - better arch-specific TRACE and TRAP handlers.
4763c99ee51aSKees Cook  * - endianness checking when appropriate
4764c99ee51aSKees Cook  * - 64-bit arg prodding
4765c99ee51aSKees Cook  * - arch value testing (x86 modes especially)
4766e66a3997STyler Hicks  * - verify that FILTER_FLAG_LOG filters generate log messages
476759f5cf44STyler Hicks  * - verify that RET_LOG generates log messages
4768c99ee51aSKees Cook  */
4769c99ee51aSKees Cook 
4770c99ee51aSKees Cook TEST_HARNESS_MAIN
4771