162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Test code for seccomp bpf.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define _GNU_SOURCE
962306a36Sopenharmony_ci#include <sys/types.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * glibc 2.26 and later have SIGSYS in siginfo_t. Before that,
1362306a36Sopenharmony_ci * we need to use the kernel's siginfo.h file and trick glibc
1462306a36Sopenharmony_ci * into accepting it.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci#if !__GLIBC_PREREQ(2, 26)
1762306a36Sopenharmony_ci# include <asm/siginfo.h>
1862306a36Sopenharmony_ci# define __have_siginfo_t 1
1962306a36Sopenharmony_ci# define __have_sigval_t 1
2062306a36Sopenharmony_ci# define __have_sigevent_t 1
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <errno.h>
2462306a36Sopenharmony_ci#include <linux/filter.h>
2562306a36Sopenharmony_ci#include <sys/prctl.h>
2662306a36Sopenharmony_ci#include <sys/ptrace.h>
2762306a36Sopenharmony_ci#include <sys/user.h>
2862306a36Sopenharmony_ci#include <linux/prctl.h>
2962306a36Sopenharmony_ci#include <linux/ptrace.h>
3062306a36Sopenharmony_ci#include <linux/seccomp.h>
3162306a36Sopenharmony_ci#include <pthread.h>
3262306a36Sopenharmony_ci#include <semaphore.h>
3362306a36Sopenharmony_ci#include <signal.h>
3462306a36Sopenharmony_ci#include <stddef.h>
3562306a36Sopenharmony_ci#include <stdbool.h>
3662306a36Sopenharmony_ci#include <string.h>
3762306a36Sopenharmony_ci#include <time.h>
3862306a36Sopenharmony_ci#include <limits.h>
3962306a36Sopenharmony_ci#include <linux/elf.h>
4062306a36Sopenharmony_ci#include <sys/uio.h>
4162306a36Sopenharmony_ci#include <sys/utsname.h>
4262306a36Sopenharmony_ci#include <sys/fcntl.h>
4362306a36Sopenharmony_ci#include <sys/mman.h>
4462306a36Sopenharmony_ci#include <sys/times.h>
4562306a36Sopenharmony_ci#include <sys/socket.h>
4662306a36Sopenharmony_ci#include <sys/ioctl.h>
4762306a36Sopenharmony_ci#include <linux/kcmp.h>
4862306a36Sopenharmony_ci#include <sys/resource.h>
4962306a36Sopenharmony_ci#include <sys/capability.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#include <unistd.h>
5262306a36Sopenharmony_ci#include <sys/syscall.h>
5362306a36Sopenharmony_ci#include <poll.h>
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#include "../kselftest_harness.h"
5662306a36Sopenharmony_ci#include "../clone3/clone3_selftests.h"
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* Attempt to de-conflict with the selftests tree. */
5962306a36Sopenharmony_ci#ifndef SKIP
6062306a36Sopenharmony_ci#define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
6162306a36Sopenharmony_ci#endif
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#ifndef PR_SET_PTRACER
6662306a36Sopenharmony_ci# define PR_SET_PTRACER 0x59616d61
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#ifndef PR_SET_NO_NEW_PRIVS
7062306a36Sopenharmony_ci#define PR_SET_NO_NEW_PRIVS 38
7162306a36Sopenharmony_ci#define PR_GET_NO_NEW_PRIVS 39
7262306a36Sopenharmony_ci#endif
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#ifndef PR_SECCOMP_EXT
7562306a36Sopenharmony_ci#define PR_SECCOMP_EXT 43
7662306a36Sopenharmony_ci#endif
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#ifndef SECCOMP_EXT_ACT
7962306a36Sopenharmony_ci#define SECCOMP_EXT_ACT 1
8062306a36Sopenharmony_ci#endif
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#ifndef SECCOMP_EXT_ACT_TSYNC
8362306a36Sopenharmony_ci#define SECCOMP_EXT_ACT_TSYNC 1
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#ifndef SECCOMP_MODE_STRICT
8762306a36Sopenharmony_ci#define SECCOMP_MODE_STRICT 1
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#ifndef SECCOMP_MODE_FILTER
9162306a36Sopenharmony_ci#define SECCOMP_MODE_FILTER 2
9262306a36Sopenharmony_ci#endif
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#ifndef SECCOMP_RET_ALLOW
9562306a36Sopenharmony_cistruct seccomp_data {
9662306a36Sopenharmony_ci	int nr;
9762306a36Sopenharmony_ci	__u32 arch;
9862306a36Sopenharmony_ci	__u64 instruction_pointer;
9962306a36Sopenharmony_ci	__u64 args[6];
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci#endif
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#ifndef SECCOMP_RET_KILL_PROCESS
10462306a36Sopenharmony_ci#define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */
10562306a36Sopenharmony_ci#define SECCOMP_RET_KILL_THREAD	 0x00000000U /* kill the thread */
10662306a36Sopenharmony_ci#endif
10762306a36Sopenharmony_ci#ifndef SECCOMP_RET_KILL
10862306a36Sopenharmony_ci#define SECCOMP_RET_KILL	 SECCOMP_RET_KILL_THREAD
10962306a36Sopenharmony_ci#define SECCOMP_RET_TRAP	 0x00030000U /* disallow and force a SIGSYS */
11062306a36Sopenharmony_ci#define SECCOMP_RET_ERRNO	 0x00050000U /* returns an errno */
11162306a36Sopenharmony_ci#define SECCOMP_RET_TRACE	 0x7ff00000U /* pass to a tracer or disallow */
11262306a36Sopenharmony_ci#define SECCOMP_RET_ALLOW	 0x7fff0000U /* allow */
11362306a36Sopenharmony_ci#endif
11462306a36Sopenharmony_ci#ifndef SECCOMP_RET_LOG
11562306a36Sopenharmony_ci#define SECCOMP_RET_LOG		 0x7ffc0000U /* allow after logging */
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#ifndef __NR_seccomp
11962306a36Sopenharmony_ci# if defined(__i386__)
12062306a36Sopenharmony_ci#  define __NR_seccomp 354
12162306a36Sopenharmony_ci# elif defined(__x86_64__)
12262306a36Sopenharmony_ci#  define __NR_seccomp 317
12362306a36Sopenharmony_ci# elif defined(__arm__)
12462306a36Sopenharmony_ci#  define __NR_seccomp 383
12562306a36Sopenharmony_ci# elif defined(__aarch64__)
12662306a36Sopenharmony_ci#  define __NR_seccomp 277
12762306a36Sopenharmony_ci# elif defined(__riscv)
12862306a36Sopenharmony_ci#  define __NR_seccomp 277
12962306a36Sopenharmony_ci# elif defined(__csky__)
13062306a36Sopenharmony_ci#  define __NR_seccomp 277
13162306a36Sopenharmony_ci# elif defined(__loongarch__)
13262306a36Sopenharmony_ci#  define __NR_seccomp 277
13362306a36Sopenharmony_ci# elif defined(__hppa__)
13462306a36Sopenharmony_ci#  define __NR_seccomp 338
13562306a36Sopenharmony_ci# elif defined(__powerpc__)
13662306a36Sopenharmony_ci#  define __NR_seccomp 358
13762306a36Sopenharmony_ci# elif defined(__s390__)
13862306a36Sopenharmony_ci#  define __NR_seccomp 348
13962306a36Sopenharmony_ci# elif defined(__xtensa__)
14062306a36Sopenharmony_ci#  define __NR_seccomp 337
14162306a36Sopenharmony_ci# elif defined(__sh__)
14262306a36Sopenharmony_ci#  define __NR_seccomp 372
14362306a36Sopenharmony_ci# elif defined(__mc68000__)
14462306a36Sopenharmony_ci#  define __NR_seccomp 380
14562306a36Sopenharmony_ci# else
14662306a36Sopenharmony_ci#  warning "seccomp syscall number unknown for this architecture"
14762306a36Sopenharmony_ci#  define __NR_seccomp 0xffff
14862306a36Sopenharmony_ci# endif
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#ifndef SECCOMP_SET_MODE_STRICT
15262306a36Sopenharmony_ci#define SECCOMP_SET_MODE_STRICT 0
15362306a36Sopenharmony_ci#endif
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#ifndef SECCOMP_SET_MODE_FILTER
15662306a36Sopenharmony_ci#define SECCOMP_SET_MODE_FILTER 1
15762306a36Sopenharmony_ci#endif
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#ifndef SECCOMP_GET_ACTION_AVAIL
16062306a36Sopenharmony_ci#define SECCOMP_GET_ACTION_AVAIL 2
16162306a36Sopenharmony_ci#endif
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#ifndef SECCOMP_GET_NOTIF_SIZES
16462306a36Sopenharmony_ci#define SECCOMP_GET_NOTIF_SIZES 3
16562306a36Sopenharmony_ci#endif
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#ifndef SECCOMP_FILTER_FLAG_TSYNC
16862306a36Sopenharmony_ci#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
16962306a36Sopenharmony_ci#endif
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#ifndef SECCOMP_FILTER_FLAG_LOG
17262306a36Sopenharmony_ci#define SECCOMP_FILTER_FLAG_LOG (1UL << 1)
17362306a36Sopenharmony_ci#endif
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW
17662306a36Sopenharmony_ci#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
17762306a36Sopenharmony_ci#endif
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci#ifndef PTRACE_SECCOMP_GET_METADATA
18062306a36Sopenharmony_ci#define PTRACE_SECCOMP_GET_METADATA	0x420d
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistruct seccomp_metadata {
18362306a36Sopenharmony_ci	__u64 filter_off;       /* Input: which filter */
18462306a36Sopenharmony_ci	__u64 flags;             /* Output: filter's flags */
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci#endif
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci#ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
18962306a36Sopenharmony_ci#define SECCOMP_FILTER_FLAG_NEW_LISTENER	(1UL << 3)
19062306a36Sopenharmony_ci#endif
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#ifndef SECCOMP_RET_USER_NOTIF
19362306a36Sopenharmony_ci#define SECCOMP_RET_USER_NOTIF 0x7fc00000U
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define SECCOMP_IOC_MAGIC		'!'
19662306a36Sopenharmony_ci#define SECCOMP_IO(nr)			_IO(SECCOMP_IOC_MAGIC, nr)
19762306a36Sopenharmony_ci#define SECCOMP_IOR(nr, type)		_IOR(SECCOMP_IOC_MAGIC, nr, type)
19862306a36Sopenharmony_ci#define SECCOMP_IOW(nr, type)		_IOW(SECCOMP_IOC_MAGIC, nr, type)
19962306a36Sopenharmony_ci#define SECCOMP_IOWR(nr, type)		_IOWR(SECCOMP_IOC_MAGIC, nr, type)
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Flags for seccomp notification fd ioctl. */
20262306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_RECV	SECCOMP_IOWR(0, struct seccomp_notif)
20362306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_SEND	SECCOMP_IOWR(1,	\
20462306a36Sopenharmony_ci						struct seccomp_notif_resp)
20562306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_ID_VALID	SECCOMP_IOW(2, __u64)
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistruct seccomp_notif {
20862306a36Sopenharmony_ci	__u64 id;
20962306a36Sopenharmony_ci	__u32 pid;
21062306a36Sopenharmony_ci	__u32 flags;
21162306a36Sopenharmony_ci	struct seccomp_data data;
21262306a36Sopenharmony_ci};
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistruct seccomp_notif_resp {
21562306a36Sopenharmony_ci	__u64 id;
21662306a36Sopenharmony_ci	__s64 val;
21762306a36Sopenharmony_ci	__s32 error;
21862306a36Sopenharmony_ci	__u32 flags;
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct seccomp_notif_sizes {
22262306a36Sopenharmony_ci	__u16 seccomp_notif;
22362306a36Sopenharmony_ci	__u16 seccomp_notif_resp;
22462306a36Sopenharmony_ci	__u16 seccomp_data;
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci#endif
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#ifndef SECCOMP_IOCTL_NOTIF_ADDFD
22962306a36Sopenharmony_ci/* On success, the return value is the remote process's added fd number */
23062306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_ADDFD	SECCOMP_IOW(3,	\
23162306a36Sopenharmony_ci						struct seccomp_notif_addfd)
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* valid flags for seccomp_notif_addfd */
23462306a36Sopenharmony_ci#define SECCOMP_ADDFD_FLAG_SETFD	(1UL << 0) /* Specify remote fd */
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistruct seccomp_notif_addfd {
23762306a36Sopenharmony_ci	__u64 id;
23862306a36Sopenharmony_ci	__u32 flags;
23962306a36Sopenharmony_ci	__u32 srcfd;
24062306a36Sopenharmony_ci	__u32 newfd;
24162306a36Sopenharmony_ci	__u32 newfd_flags;
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci#endif
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#ifndef SECCOMP_ADDFD_FLAG_SEND
24662306a36Sopenharmony_ci#define SECCOMP_ADDFD_FLAG_SEND	(1UL << 1) /* Addfd and return it, atomically */
24762306a36Sopenharmony_ci#endif
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistruct seccomp_notif_addfd_small {
25062306a36Sopenharmony_ci	__u64 id;
25162306a36Sopenharmony_ci	char weird[4];
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_ADDFD_SMALL	\
25462306a36Sopenharmony_ci	SECCOMP_IOW(3, struct seccomp_notif_addfd_small)
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistruct seccomp_notif_addfd_big {
25762306a36Sopenharmony_ci	union {
25862306a36Sopenharmony_ci		struct seccomp_notif_addfd addfd;
25962306a36Sopenharmony_ci		char buf[sizeof(struct seccomp_notif_addfd) + 8];
26062306a36Sopenharmony_ci	};
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_ADDFD_BIG	\
26362306a36Sopenharmony_ci	SECCOMP_IOWR(3, struct seccomp_notif_addfd_big)
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#ifndef PTRACE_EVENTMSG_SYSCALL_ENTRY
26662306a36Sopenharmony_ci#define PTRACE_EVENTMSG_SYSCALL_ENTRY	1
26762306a36Sopenharmony_ci#define PTRACE_EVENTMSG_SYSCALL_EXIT	2
26862306a36Sopenharmony_ci#endif
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci#ifndef SECCOMP_USER_NOTIF_FLAG_CONTINUE
27162306a36Sopenharmony_ci#define SECCOMP_USER_NOTIF_FLAG_CONTINUE 0x00000001
27262306a36Sopenharmony_ci#endif
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#ifndef SECCOMP_FILTER_FLAG_TSYNC_ESRCH
27562306a36Sopenharmony_ci#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4)
27662306a36Sopenharmony_ci#endif
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci#ifndef SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV
27962306a36Sopenharmony_ci#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5)
28062306a36Sopenharmony_ci#endif
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#ifndef seccomp
28362306a36Sopenharmony_ciint seccomp(unsigned int op, unsigned int flags, void *args)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	errno = 0;
28662306a36Sopenharmony_ci	return syscall(__NR_seccomp, op, flags, args);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci#endif
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
29162306a36Sopenharmony_ci#define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]))
29262306a36Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
29362306a36Sopenharmony_ci#define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]) + sizeof(__u32))
29462306a36Sopenharmony_ci#else
29562306a36Sopenharmony_ci#error "wut? Unknown __BYTE_ORDER__?!"
29662306a36Sopenharmony_ci#endif
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#define SIBLING_EXIT_UNKILLED	0xbadbeef
29962306a36Sopenharmony_ci#define SIBLING_EXIT_FAILURE	0xbadface
30062306a36Sopenharmony_ci#define SIBLING_EXIT_NEWPRIVS	0xbadfeed
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int __filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci#ifdef __NR_kcmp
30562306a36Sopenharmony_ci	errno = 0;
30662306a36Sopenharmony_ci	return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
30762306a36Sopenharmony_ci#else
30862306a36Sopenharmony_ci	errno = ENOSYS;
30962306a36Sopenharmony_ci	return -1;
31062306a36Sopenharmony_ci#endif
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci/* Have TH_LOG report actual location filecmp() is used. */
31462306a36Sopenharmony_ci#define filecmp(pid1, pid2, fd1, fd2)	({		\
31562306a36Sopenharmony_ci	int _ret;					\
31662306a36Sopenharmony_ci							\
31762306a36Sopenharmony_ci	_ret = __filecmp(pid1, pid2, fd1, fd2);		\
31862306a36Sopenharmony_ci	if (_ret != 0) {				\
31962306a36Sopenharmony_ci		if (_ret < 0 && errno == ENOSYS) {	\
32062306a36Sopenharmony_ci			TH_LOG("kcmp() syscall missing (test is less accurate)");\
32162306a36Sopenharmony_ci			_ret = 0;			\
32262306a36Sopenharmony_ci		}					\
32362306a36Sopenharmony_ci	}						\
32462306a36Sopenharmony_ci	_ret; })
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciTEST(kcmp)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	int ret;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	ret = __filecmp(getpid(), getpid(), 1, 1);
33162306a36Sopenharmony_ci	EXPECT_EQ(ret, 0);
33262306a36Sopenharmony_ci	if (ret != 0 && errno == ENOSYS)
33362306a36Sopenharmony_ci		SKIP(return, "Kernel does not support kcmp() (missing CONFIG_KCMP?)");
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ciTEST(mode_strict_support)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	long ret;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, NULL, NULL);
34162306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
34262306a36Sopenharmony_ci		TH_LOG("Kernel does not support CONFIG_SECCOMP");
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	syscall(__NR_exit, 0);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ciTEST_SIGNAL(mode_strict_cannot_call_prctl, SIGKILL)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	long ret;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, NULL, NULL);
35262306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
35362306a36Sopenharmony_ci		TH_LOG("Kernel does not support CONFIG_SECCOMP");
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	syscall(__NR_prctl, PR_SET_SECCOMP, SECCOMP_MODE_FILTER,
35662306a36Sopenharmony_ci		NULL, NULL, NULL);
35762306a36Sopenharmony_ci	EXPECT_FALSE(true) {
35862306a36Sopenharmony_ci		TH_LOG("Unreachable!");
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/* Note! This doesn't test no new privs behavior */
36362306a36Sopenharmony_ciTEST(no_new_privs_support)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	long ret;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
36862306a36Sopenharmony_ci	EXPECT_EQ(0, ret) {
36962306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/* Tests kernel support by checking for a copy_from_user() fault on NULL. */
37462306a36Sopenharmony_ciTEST(mode_filter_support)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	long ret;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
37962306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
38062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, NULL, NULL);
38362306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
38462306a36Sopenharmony_ci	EXPECT_EQ(EFAULT, errno) {
38562306a36Sopenharmony_ci		TH_LOG("Kernel does not support CONFIG_SECCOMP_FILTER!");
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciTEST(mode_filter_without_nnp)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct sock_filter filter[] = {
39262306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
39362306a36Sopenharmony_ci	};
39462306a36Sopenharmony_ci	struct sock_fprog prog = {
39562306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
39662306a36Sopenharmony_ci		.filter = filter,
39762306a36Sopenharmony_ci	};
39862306a36Sopenharmony_ci	long ret;
39962306a36Sopenharmony_ci	cap_t cap = cap_get_proc();
40062306a36Sopenharmony_ci	cap_flag_value_t is_cap_sys_admin = 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	ret = prctl(PR_GET_NO_NEW_PRIVS, 0, NULL, 0, 0);
40362306a36Sopenharmony_ci	ASSERT_LE(0, ret) {
40462306a36Sopenharmony_ci		TH_LOG("Expected 0 or unsupported for NO_NEW_PRIVS");
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	errno = 0;
40762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
40862306a36Sopenharmony_ci	/* Succeeds with CAP_SYS_ADMIN, fails without */
40962306a36Sopenharmony_ci	cap_get_flag(cap, CAP_SYS_ADMIN, CAP_EFFECTIVE, &is_cap_sys_admin);
41062306a36Sopenharmony_ci	if (!is_cap_sys_admin) {
41162306a36Sopenharmony_ci		EXPECT_EQ(-1, ret);
41262306a36Sopenharmony_ci		EXPECT_EQ(EACCES, errno);
41362306a36Sopenharmony_ci	} else {
41462306a36Sopenharmony_ci		EXPECT_EQ(0, ret);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci#define MAX_INSNS_PER_PATH 32768
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ciTEST(filter_size_limits)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	int i;
42362306a36Sopenharmony_ci	int count = BPF_MAXINSNS + 1;
42462306a36Sopenharmony_ci	struct sock_filter allow[] = {
42562306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
42662306a36Sopenharmony_ci	};
42762306a36Sopenharmony_ci	struct sock_filter *filter;
42862306a36Sopenharmony_ci	struct sock_fprog prog = { };
42962306a36Sopenharmony_ci	long ret;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	filter = calloc(count, sizeof(*filter));
43262306a36Sopenharmony_ci	ASSERT_NE(NULL, filter);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	for (i = 0; i < count; i++)
43562306a36Sopenharmony_ci		filter[i] = allow[0];
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
43862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	prog.filter = filter;
44162306a36Sopenharmony_ci	prog.len = count;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/* Too many filter instructions in a single filter. */
44462306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
44562306a36Sopenharmony_ci	ASSERT_NE(0, ret) {
44662306a36Sopenharmony_ci		TH_LOG("Installing %d insn filter was allowed", prog.len);
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* One less is okay, though. */
45062306a36Sopenharmony_ci	prog.len -= 1;
45162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
45262306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
45362306a36Sopenharmony_ci		TH_LOG("Installing %d insn filter wasn't allowed", prog.len);
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ciTEST(filter_chain_limits)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	int i;
46062306a36Sopenharmony_ci	int count = BPF_MAXINSNS;
46162306a36Sopenharmony_ci	struct sock_filter allow[] = {
46262306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
46362306a36Sopenharmony_ci	};
46462306a36Sopenharmony_ci	struct sock_filter *filter;
46562306a36Sopenharmony_ci	struct sock_fprog prog = { };
46662306a36Sopenharmony_ci	long ret;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	filter = calloc(count, sizeof(*filter));
46962306a36Sopenharmony_ci	ASSERT_NE(NULL, filter);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	for (i = 0; i < count; i++)
47262306a36Sopenharmony_ci		filter[i] = allow[0];
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
47562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	prog.filter = filter;
47862306a36Sopenharmony_ci	prog.len = 1;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
48162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	prog.len = count;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* Too many total filter instructions. */
48662306a36Sopenharmony_ci	for (i = 0; i < MAX_INSNS_PER_PATH; i++) {
48762306a36Sopenharmony_ci		ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
48862306a36Sopenharmony_ci		if (ret != 0)
48962306a36Sopenharmony_ci			break;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci	ASSERT_NE(0, ret) {
49262306a36Sopenharmony_ci		TH_LOG("Allowed %d %d-insn filters (total with penalties:%d)",
49362306a36Sopenharmony_ci		       i, count, i * (count + 4));
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ciTEST(mode_filter_cannot_move_to_strict)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	struct sock_filter filter[] = {
50062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
50162306a36Sopenharmony_ci	};
50262306a36Sopenharmony_ci	struct sock_fprog prog = {
50362306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
50462306a36Sopenharmony_ci		.filter = filter,
50562306a36Sopenharmony_ci	};
50662306a36Sopenharmony_ci	long ret;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
50962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
51262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0);
51562306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
51662306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno);
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ciTEST(mode_filter_get_seccomp)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct sock_filter filter[] = {
52362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
52462306a36Sopenharmony_ci	};
52562306a36Sopenharmony_ci	struct sock_fprog prog = {
52662306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
52762306a36Sopenharmony_ci		.filter = filter,
52862306a36Sopenharmony_ci	};
52962306a36Sopenharmony_ci	long ret;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
53262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
53562306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
53862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
54162306a36Sopenharmony_ci	EXPECT_EQ(2, ret);
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ciTEST(ALLOW_all)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct sock_filter filter[] = {
54862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
54962306a36Sopenharmony_ci	};
55062306a36Sopenharmony_ci	struct sock_fprog prog = {
55162306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
55262306a36Sopenharmony_ci		.filter = filter,
55362306a36Sopenharmony_ci	};
55462306a36Sopenharmony_ci	long ret;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
55762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
56062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ciTEST(empty_prog)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct sock_filter filter[] = {
56662306a36Sopenharmony_ci	};
56762306a36Sopenharmony_ci	struct sock_fprog prog = {
56862306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
56962306a36Sopenharmony_ci		.filter = filter,
57062306a36Sopenharmony_ci	};
57162306a36Sopenharmony_ci	long ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
57462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
57762306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
57862306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ciTEST(log_all)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct sock_filter filter[] = {
58462306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG),
58562306a36Sopenharmony_ci	};
58662306a36Sopenharmony_ci	struct sock_fprog prog = {
58762306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
58862306a36Sopenharmony_ci		.filter = filter,
58962306a36Sopenharmony_ci	};
59062306a36Sopenharmony_ci	long ret;
59162306a36Sopenharmony_ci	pid_t parent = getppid();
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
59462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
59762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* getppid() should succeed and be logged (no check for logging) */
60062306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ciTEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct sock_filter filter[] = {
60662306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, 0x10000000U),
60762306a36Sopenharmony_ci	};
60862306a36Sopenharmony_ci	struct sock_fprog prog = {
60962306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
61062306a36Sopenharmony_ci		.filter = filter,
61162306a36Sopenharmony_ci	};
61262306a36Sopenharmony_ci	long ret;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
61562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
61862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
61962306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid)) {
62062306a36Sopenharmony_ci		TH_LOG("getpid() shouldn't ever return");
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci/* return code >= 0x80000000 is unused. */
62562306a36Sopenharmony_ciTEST_SIGNAL(unknown_ret_is_kill_above_allow, SIGSYS)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct sock_filter filter[] = {
62862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, 0x90000000U),
62962306a36Sopenharmony_ci	};
63062306a36Sopenharmony_ci	struct sock_fprog prog = {
63162306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
63262306a36Sopenharmony_ci		.filter = filter,
63362306a36Sopenharmony_ci	};
63462306a36Sopenharmony_ci	long ret;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
63762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
64062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
64162306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid)) {
64262306a36Sopenharmony_ci		TH_LOG("getpid() shouldn't ever return");
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ciTEST_SIGNAL(KILL_all, SIGSYS)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct sock_filter filter[] = {
64962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
65062306a36Sopenharmony_ci	};
65162306a36Sopenharmony_ci	struct sock_fprog prog = {
65262306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
65362306a36Sopenharmony_ci		.filter = filter,
65462306a36Sopenharmony_ci	};
65562306a36Sopenharmony_ci	long ret;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
65862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
66162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ciTEST_SIGNAL(KILL_one, SIGSYS)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct sock_filter filter[] = {
66762306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
66862306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
66962306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
67062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
67162306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
67262306a36Sopenharmony_ci	};
67362306a36Sopenharmony_ci	struct sock_fprog prog = {
67462306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
67562306a36Sopenharmony_ci		.filter = filter,
67662306a36Sopenharmony_ci	};
67762306a36Sopenharmony_ci	long ret;
67862306a36Sopenharmony_ci	pid_t parent = getppid();
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
68162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
68462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
68762306a36Sopenharmony_ci	/* getpid() should never return. */
68862306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ciTEST_SIGNAL(KILL_one_arg_one, SIGSYS)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	void *fatal_address;
69462306a36Sopenharmony_ci	struct sock_filter filter[] = {
69562306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
69662306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
69762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_times, 1, 0),
69862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
69962306a36Sopenharmony_ci		/* Only both with lower 32-bit for now. */
70062306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)),
70162306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K,
70262306a36Sopenharmony_ci			(unsigned long)&fatal_address, 0, 1),
70362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
70462306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
70562306a36Sopenharmony_ci	};
70662306a36Sopenharmony_ci	struct sock_fprog prog = {
70762306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
70862306a36Sopenharmony_ci		.filter = filter,
70962306a36Sopenharmony_ci	};
71062306a36Sopenharmony_ci	long ret;
71162306a36Sopenharmony_ci	pid_t parent = getppid();
71262306a36Sopenharmony_ci	struct tms timebuf;
71362306a36Sopenharmony_ci	clock_t clock = times(&timebuf);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
71662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
71962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
72262306a36Sopenharmony_ci	EXPECT_LE(clock, syscall(__NR_times, &timebuf));
72362306a36Sopenharmony_ci	/* times() should never return. */
72462306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_times, &fatal_address));
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ciTEST_SIGNAL(KILL_one_arg_six, SIGSYS)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci#ifndef __NR_mmap2
73062306a36Sopenharmony_ci	int sysno = __NR_mmap;
73162306a36Sopenharmony_ci#else
73262306a36Sopenharmony_ci	int sysno = __NR_mmap2;
73362306a36Sopenharmony_ci#endif
73462306a36Sopenharmony_ci	struct sock_filter filter[] = {
73562306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
73662306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
73762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sysno, 1, 0),
73862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
73962306a36Sopenharmony_ci		/* Only both with lower 32-bit for now. */
74062306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)),
74162306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1),
74262306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
74362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
74462306a36Sopenharmony_ci	};
74562306a36Sopenharmony_ci	struct sock_fprog prog = {
74662306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
74762306a36Sopenharmony_ci		.filter = filter,
74862306a36Sopenharmony_ci	};
74962306a36Sopenharmony_ci	long ret;
75062306a36Sopenharmony_ci	pid_t parent = getppid();
75162306a36Sopenharmony_ci	int fd;
75262306a36Sopenharmony_ci	void *map1, *map2;
75362306a36Sopenharmony_ci	int page_size = sysconf(_SC_PAGESIZE);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	ASSERT_LT(0, page_size);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
75862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
76162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	fd = open("/dev/zero", O_RDONLY);
76462306a36Sopenharmony_ci	ASSERT_NE(-1, fd);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
76762306a36Sopenharmony_ci	map1 = (void *)syscall(sysno,
76862306a36Sopenharmony_ci		NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size);
76962306a36Sopenharmony_ci	EXPECT_NE(MAP_FAILED, map1);
77062306a36Sopenharmony_ci	/* mmap2() should never return. */
77162306a36Sopenharmony_ci	map2 = (void *)syscall(sysno,
77262306a36Sopenharmony_ci		 NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
77362306a36Sopenharmony_ci	EXPECT_EQ(MAP_FAILED, map2);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* The test failed, so clean up the resources. */
77662306a36Sopenharmony_ci	munmap(map1, page_size);
77762306a36Sopenharmony_ci	munmap(map2, page_size);
77862306a36Sopenharmony_ci	close(fd);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/* This is a thread task to die via seccomp filter violation. */
78262306a36Sopenharmony_civoid *kill_thread(void *data)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	bool die = (bool)data;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (die) {
78762306a36Sopenharmony_ci		prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
78862306a36Sopenharmony_ci		return (void *)SIBLING_EXIT_FAILURE;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	return (void *)SIBLING_EXIT_UNKILLED;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cienum kill_t {
79562306a36Sopenharmony_ci	KILL_THREAD,
79662306a36Sopenharmony_ci	KILL_PROCESS,
79762306a36Sopenharmony_ci	RET_UNKNOWN
79862306a36Sopenharmony_ci};
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci/* Prepare a thread that will kill itself or both of us. */
80162306a36Sopenharmony_civoid kill_thread_or_group(struct __test_metadata *_metadata,
80262306a36Sopenharmony_ci			  enum kill_t kill_how)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	pthread_t thread;
80562306a36Sopenharmony_ci	void *status;
80662306a36Sopenharmony_ci	/* Kill only when calling __NR_prctl. */
80762306a36Sopenharmony_ci	struct sock_filter filter_thread[] = {
80862306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
80962306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
81062306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1),
81162306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD),
81262306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
81362306a36Sopenharmony_ci	};
81462306a36Sopenharmony_ci	struct sock_fprog prog_thread = {
81562306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter_thread),
81662306a36Sopenharmony_ci		.filter = filter_thread,
81762306a36Sopenharmony_ci	};
81862306a36Sopenharmony_ci	int kill = kill_how == KILL_PROCESS ? SECCOMP_RET_KILL_PROCESS : 0xAAAAAAAA;
81962306a36Sopenharmony_ci	struct sock_filter filter_process[] = {
82062306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
82162306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
82262306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1),
82362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, kill),
82462306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
82562306a36Sopenharmony_ci	};
82662306a36Sopenharmony_ci	struct sock_fprog prog_process = {
82762306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter_process),
82862306a36Sopenharmony_ci		.filter = filter_process,
82962306a36Sopenharmony_ci	};
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
83262306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0,
83662306a36Sopenharmony_ci			     kill_how == KILL_THREAD ? &prog_thread
83762306a36Sopenharmony_ci						     : &prog_process));
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/*
84062306a36Sopenharmony_ci	 * Add the KILL_THREAD rule again to make sure that the KILL_PROCESS
84162306a36Sopenharmony_ci	 * flag cannot be downgraded by a new filter.
84262306a36Sopenharmony_ci	 */
84362306a36Sopenharmony_ci	if (kill_how == KILL_PROCESS)
84462306a36Sopenharmony_ci		ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog_thread));
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	/* Start a thread that will exit immediately. */
84762306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)false));
84862306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_join(thread, &status));
84962306a36Sopenharmony_ci	ASSERT_EQ(SIBLING_EXIT_UNKILLED, (unsigned long)status);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* Start a thread that will die immediately. */
85262306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)true));
85362306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_join(thread, &status));
85462306a36Sopenharmony_ci	ASSERT_NE(SIBLING_EXIT_FAILURE, (unsigned long)status);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	/*
85762306a36Sopenharmony_ci	 * If we get here, only the spawned thread died. Let the parent know
85862306a36Sopenharmony_ci	 * the whole process didn't die (i.e. this thread, the spawner,
85962306a36Sopenharmony_ci	 * stayed running).
86062306a36Sopenharmony_ci	 */
86162306a36Sopenharmony_ci	exit(42);
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ciTEST(KILL_thread)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	int status;
86762306a36Sopenharmony_ci	pid_t child_pid;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	child_pid = fork();
87062306a36Sopenharmony_ci	ASSERT_LE(0, child_pid);
87162306a36Sopenharmony_ci	if (child_pid == 0) {
87262306a36Sopenharmony_ci		kill_thread_or_group(_metadata, KILL_THREAD);
87362306a36Sopenharmony_ci		_exit(38);
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* If only the thread was killed, we'll see exit 42. */
87962306a36Sopenharmony_ci	ASSERT_TRUE(WIFEXITED(status));
88062306a36Sopenharmony_ci	ASSERT_EQ(42, WEXITSTATUS(status));
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ciTEST(KILL_process)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	int status;
88662306a36Sopenharmony_ci	pid_t child_pid;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	child_pid = fork();
88962306a36Sopenharmony_ci	ASSERT_LE(0, child_pid);
89062306a36Sopenharmony_ci	if (child_pid == 0) {
89162306a36Sopenharmony_ci		kill_thread_or_group(_metadata, KILL_PROCESS);
89262306a36Sopenharmony_ci		_exit(38);
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* If the entire process was killed, we'll see SIGSYS. */
89862306a36Sopenharmony_ci	ASSERT_TRUE(WIFSIGNALED(status));
89962306a36Sopenharmony_ci	ASSERT_EQ(SIGSYS, WTERMSIG(status));
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ciTEST(KILL_unknown)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	int status;
90562306a36Sopenharmony_ci	pid_t child_pid;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	child_pid = fork();
90862306a36Sopenharmony_ci	ASSERT_LE(0, child_pid);
90962306a36Sopenharmony_ci	if (child_pid == 0) {
91062306a36Sopenharmony_ci		kill_thread_or_group(_metadata, RET_UNKNOWN);
91162306a36Sopenharmony_ci		_exit(38);
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* If the entire process was killed, we'll see SIGSYS. */
91762306a36Sopenharmony_ci	EXPECT_TRUE(WIFSIGNALED(status)) {
91862306a36Sopenharmony_ci		TH_LOG("Unknown SECCOMP_RET is only killing the thread?");
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci	ASSERT_EQ(SIGSYS, WTERMSIG(status));
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci/* TODO(wad) add 64-bit versus 32-bit arg tests. */
92462306a36Sopenharmony_ciTEST(arg_out_of_range)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct sock_filter filter[] = {
92762306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(6)),
92862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
92962306a36Sopenharmony_ci	};
93062306a36Sopenharmony_ci	struct sock_fprog prog = {
93162306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
93262306a36Sopenharmony_ci		.filter = filter,
93362306a36Sopenharmony_ci	};
93462306a36Sopenharmony_ci	long ret;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
93762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
94062306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
94162306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci#define ERRNO_FILTER(name, errno)					\
94562306a36Sopenharmony_ci	struct sock_filter _read_filter_##name[] = {			\
94662306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,				\
94762306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),		\
94862306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),	\
94962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | errno),	\
95062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),		\
95162306a36Sopenharmony_ci	};								\
95262306a36Sopenharmony_ci	struct sock_fprog prog_##name = {				\
95362306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(_read_filter_##name),	\
95462306a36Sopenharmony_ci		.filter = _read_filter_##name,				\
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci/* Make sure basic errno values are correctly passed through a filter. */
95862306a36Sopenharmony_ciTEST(ERRNO_valid)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	ERRNO_FILTER(valid, E2BIG);
96162306a36Sopenharmony_ci	long ret;
96262306a36Sopenharmony_ci	pid_t parent = getppid();
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
96562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_valid);
96862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
97162306a36Sopenharmony_ci	EXPECT_EQ(-1, read(-1, NULL, 0));
97262306a36Sopenharmony_ci	EXPECT_EQ(E2BIG, errno);
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci/* Make sure an errno of zero is correctly handled by the arch code. */
97662306a36Sopenharmony_ciTEST(ERRNO_zero)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	ERRNO_FILTER(zero, 0);
97962306a36Sopenharmony_ci	long ret;
98062306a36Sopenharmony_ci	pid_t parent = getppid();
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
98362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_zero);
98662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
98962306a36Sopenharmony_ci	/* "errno" of 0 is ok. */
99062306a36Sopenharmony_ci	EXPECT_EQ(0, read(-1, NULL, 0));
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci/*
99462306a36Sopenharmony_ci * The SECCOMP_RET_DATA mask is 16 bits wide, but errno is smaller.
99562306a36Sopenharmony_ci * This tests that the errno value gets capped correctly, fixed by
99662306a36Sopenharmony_ci * 580c57f10768 ("seccomp: cap SECCOMP_RET_ERRNO data to MAX_ERRNO").
99762306a36Sopenharmony_ci */
99862306a36Sopenharmony_ciTEST(ERRNO_capped)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	ERRNO_FILTER(capped, 4096);
100162306a36Sopenharmony_ci	long ret;
100262306a36Sopenharmony_ci	pid_t parent = getppid();
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
100562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_capped);
100862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
101162306a36Sopenharmony_ci	EXPECT_EQ(-1, read(-1, NULL, 0));
101262306a36Sopenharmony_ci	EXPECT_EQ(4095, errno);
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci/*
101662306a36Sopenharmony_ci * Filters are processed in reverse order: last applied is executed first.
101762306a36Sopenharmony_ci * Since only the SECCOMP_RET_ACTION mask is tested for return values, the
101862306a36Sopenharmony_ci * SECCOMP_RET_DATA mask results will follow the most recently applied
101962306a36Sopenharmony_ci * matching filter return (and not the lowest or highest value).
102062306a36Sopenharmony_ci */
102162306a36Sopenharmony_ciTEST(ERRNO_order)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	ERRNO_FILTER(first,  11);
102462306a36Sopenharmony_ci	ERRNO_FILTER(second, 13);
102562306a36Sopenharmony_ci	ERRNO_FILTER(third,  12);
102662306a36Sopenharmony_ci	long ret;
102762306a36Sopenharmony_ci	pid_t parent = getppid();
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
103062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_first);
103362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_second);
103662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_third);
103962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
104262306a36Sopenharmony_ci	EXPECT_EQ(-1, read(-1, NULL, 0));
104362306a36Sopenharmony_ci	EXPECT_EQ(12, errno);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ciFIXTURE(TRAP) {
104762306a36Sopenharmony_ci	struct sock_fprog prog;
104862306a36Sopenharmony_ci};
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ciFIXTURE_SETUP(TRAP)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct sock_filter filter[] = {
105362306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
105462306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
105562306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
105662306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),
105762306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
105862306a36Sopenharmony_ci	};
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	memset(&self->prog, 0, sizeof(self->prog));
106162306a36Sopenharmony_ci	self->prog.filter = malloc(sizeof(filter));
106262306a36Sopenharmony_ci	ASSERT_NE(NULL, self->prog.filter);
106362306a36Sopenharmony_ci	memcpy(self->prog.filter, filter, sizeof(filter));
106462306a36Sopenharmony_ci	self->prog.len = (unsigned short)ARRAY_SIZE(filter);
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ciFIXTURE_TEARDOWN(TRAP)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	if (self->prog.filter)
107062306a36Sopenharmony_ci		free(self->prog.filter);
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ciTEST_F_SIGNAL(TRAP, dfl, SIGSYS)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	long ret;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
107862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
108162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
108262306a36Sopenharmony_ci	syscall(__NR_getpid);
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci/* Ensure that SIGSYS overrides SIG_IGN */
108662306a36Sopenharmony_ciTEST_F_SIGNAL(TRAP, ign, SIGSYS)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	long ret;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
109162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	signal(SIGSYS, SIG_IGN);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
109662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
109762306a36Sopenharmony_ci	syscall(__NR_getpid);
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic siginfo_t TRAP_info;
110162306a36Sopenharmony_cistatic volatile int TRAP_nr;
110262306a36Sopenharmony_cistatic void TRAP_action(int nr, siginfo_t *info, void *void_context)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	memcpy(&TRAP_info, info, sizeof(TRAP_info));
110562306a36Sopenharmony_ci	TRAP_nr = nr;
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ciTEST_F(TRAP, handler)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	int ret, test;
111162306a36Sopenharmony_ci	struct sigaction act;
111262306a36Sopenharmony_ci	sigset_t mask;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	memset(&act, 0, sizeof(act));
111562306a36Sopenharmony_ci	sigemptyset(&mask);
111662306a36Sopenharmony_ci	sigaddset(&mask, SIGSYS);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	act.sa_sigaction = &TRAP_action;
111962306a36Sopenharmony_ci	act.sa_flags = SA_SIGINFO;
112062306a36Sopenharmony_ci	ret = sigaction(SIGSYS, &act, NULL);
112162306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
112262306a36Sopenharmony_ci		TH_LOG("sigaction failed");
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci	ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
112562306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
112662306a36Sopenharmony_ci		TH_LOG("sigprocmask failed");
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
113062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
113162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
113262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
113362306a36Sopenharmony_ci	TRAP_nr = 0;
113462306a36Sopenharmony_ci	memset(&TRAP_info, 0, sizeof(TRAP_info));
113562306a36Sopenharmony_ci	/* Expect the registers to be rolled back. (nr = error) may vary
113662306a36Sopenharmony_ci	 * based on arch. */
113762306a36Sopenharmony_ci	ret = syscall(__NR_getpid);
113862306a36Sopenharmony_ci	/* Silence gcc warning about volatile. */
113962306a36Sopenharmony_ci	test = TRAP_nr;
114062306a36Sopenharmony_ci	EXPECT_EQ(SIGSYS, test);
114162306a36Sopenharmony_ci	struct local_sigsys {
114262306a36Sopenharmony_ci		void *_call_addr;	/* calling user insn */
114362306a36Sopenharmony_ci		int _syscall;		/* triggering system call number */
114462306a36Sopenharmony_ci		unsigned int _arch;	/* AUDIT_ARCH_* of syscall */
114562306a36Sopenharmony_ci	} *sigsys = (struct local_sigsys *)
114662306a36Sopenharmony_ci#ifdef si_syscall
114762306a36Sopenharmony_ci		&(TRAP_info.si_call_addr);
114862306a36Sopenharmony_ci#else
114962306a36Sopenharmony_ci		&TRAP_info.si_pid;
115062306a36Sopenharmony_ci#endif
115162306a36Sopenharmony_ci	EXPECT_EQ(__NR_getpid, sigsys->_syscall);
115262306a36Sopenharmony_ci	/* Make sure arch is non-zero. */
115362306a36Sopenharmony_ci	EXPECT_NE(0, sigsys->_arch);
115462306a36Sopenharmony_ci	EXPECT_NE(0, (unsigned long)sigsys->_call_addr);
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ciFIXTURE(precedence) {
115862306a36Sopenharmony_ci	struct sock_fprog allow;
115962306a36Sopenharmony_ci	struct sock_fprog log;
116062306a36Sopenharmony_ci	struct sock_fprog trace;
116162306a36Sopenharmony_ci	struct sock_fprog error;
116262306a36Sopenharmony_ci	struct sock_fprog trap;
116362306a36Sopenharmony_ci	struct sock_fprog kill;
116462306a36Sopenharmony_ci};
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ciFIXTURE_SETUP(precedence)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	struct sock_filter allow_insns[] = {
116962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
117062306a36Sopenharmony_ci	};
117162306a36Sopenharmony_ci	struct sock_filter log_insns[] = {
117262306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
117362306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
117462306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
117562306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
117662306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG),
117762306a36Sopenharmony_ci	};
117862306a36Sopenharmony_ci	struct sock_filter trace_insns[] = {
117962306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
118062306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
118162306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
118262306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
118362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE),
118462306a36Sopenharmony_ci	};
118562306a36Sopenharmony_ci	struct sock_filter error_insns[] = {
118662306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
118762306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
118862306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
118962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
119062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO),
119162306a36Sopenharmony_ci	};
119262306a36Sopenharmony_ci	struct sock_filter trap_insns[] = {
119362306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
119462306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
119562306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
119662306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
119762306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),
119862306a36Sopenharmony_ci	};
119962306a36Sopenharmony_ci	struct sock_filter kill_insns[] = {
120062306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
120162306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
120262306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
120362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
120462306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
120562306a36Sopenharmony_ci	};
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	memset(self, 0, sizeof(*self));
120862306a36Sopenharmony_ci#define FILTER_ALLOC(_x) \
120962306a36Sopenharmony_ci	self->_x.filter = malloc(sizeof(_x##_insns)); \
121062306a36Sopenharmony_ci	ASSERT_NE(NULL, self->_x.filter); \
121162306a36Sopenharmony_ci	memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \
121262306a36Sopenharmony_ci	self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns)
121362306a36Sopenharmony_ci	FILTER_ALLOC(allow);
121462306a36Sopenharmony_ci	FILTER_ALLOC(log);
121562306a36Sopenharmony_ci	FILTER_ALLOC(trace);
121662306a36Sopenharmony_ci	FILTER_ALLOC(error);
121762306a36Sopenharmony_ci	FILTER_ALLOC(trap);
121862306a36Sopenharmony_ci	FILTER_ALLOC(kill);
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ciFIXTURE_TEARDOWN(precedence)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci#define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter)
122462306a36Sopenharmony_ci	FILTER_FREE(allow);
122562306a36Sopenharmony_ci	FILTER_FREE(log);
122662306a36Sopenharmony_ci	FILTER_FREE(trace);
122762306a36Sopenharmony_ci	FILTER_FREE(error);
122862306a36Sopenharmony_ci	FILTER_FREE(trap);
122962306a36Sopenharmony_ci	FILTER_FREE(kill);
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ciTEST_F(precedence, allow_ok)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	pid_t parent, res = 0;
123562306a36Sopenharmony_ci	long ret;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	parent = getppid();
123862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
123962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
124262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
124362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
124462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
124562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
124662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
124762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
124862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
124962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
125062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
125162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill);
125262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
125362306a36Sopenharmony_ci	/* Should work just fine. */
125462306a36Sopenharmony_ci	res = syscall(__NR_getppid);
125562306a36Sopenharmony_ci	EXPECT_EQ(parent, res);
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ciTEST_F_SIGNAL(precedence, kill_is_highest, SIGSYS)
125962306a36Sopenharmony_ci{
126062306a36Sopenharmony_ci	pid_t parent, res = 0;
126162306a36Sopenharmony_ci	long ret;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	parent = getppid();
126462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
126562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
126862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
126962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
127062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
127162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
127262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
127362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
127462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
127562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
127662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
127762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill);
127862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
127962306a36Sopenharmony_ci	/* Should work just fine. */
128062306a36Sopenharmony_ci	res = syscall(__NR_getppid);
128162306a36Sopenharmony_ci	EXPECT_EQ(parent, res);
128262306a36Sopenharmony_ci	/* getpid() should never return. */
128362306a36Sopenharmony_ci	res = syscall(__NR_getpid);
128462306a36Sopenharmony_ci	EXPECT_EQ(0, res);
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ciTEST_F_SIGNAL(precedence, kill_is_highest_in_any_order, SIGSYS)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	pid_t parent;
129062306a36Sopenharmony_ci	long ret;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	parent = getppid();
129362306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
129462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
129762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
129862306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill);
129962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
130062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
130162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
130262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
130362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
130462306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
130562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
130662306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
130762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
130862306a36Sopenharmony_ci	/* Should work just fine. */
130962306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
131062306a36Sopenharmony_ci	/* getpid() should never return. */
131162306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
131262306a36Sopenharmony_ci}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ciTEST_F_SIGNAL(precedence, trap_is_second, SIGSYS)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	pid_t parent;
131762306a36Sopenharmony_ci	long ret;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	parent = getppid();
132062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
132162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
132462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
132562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
132662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
132762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
132862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
132962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
133062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
133162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
133262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
133362306a36Sopenharmony_ci	/* Should work just fine. */
133462306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
133562306a36Sopenharmony_ci	/* getpid() should never return. */
133662306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ciTEST_F_SIGNAL(precedence, trap_is_second_in_any_order, SIGSYS)
134062306a36Sopenharmony_ci{
134162306a36Sopenharmony_ci	pid_t parent;
134262306a36Sopenharmony_ci	long ret;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	parent = getppid();
134562306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
134662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
134962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
135062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
135162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
135262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
135362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
135462306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
135562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
135662306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
135762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
135862306a36Sopenharmony_ci	/* Should work just fine. */
135962306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
136062306a36Sopenharmony_ci	/* getpid() should never return. */
136162306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ciTEST_F(precedence, errno_is_third)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	pid_t parent;
136762306a36Sopenharmony_ci	long ret;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	parent = getppid();
137062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
137162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
137462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
137562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
137662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
137762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
137862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
137962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
138062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
138162306a36Sopenharmony_ci	/* Should work just fine. */
138262306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
138362306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ciTEST_F(precedence, errno_is_third_in_any_order)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	pid_t parent;
138962306a36Sopenharmony_ci	long ret;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	parent = getppid();
139262306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
139362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
139662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
139762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
139862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
139962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
140062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
140162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
140262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
140362306a36Sopenharmony_ci	/* Should work just fine. */
140462306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
140562306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
140662306a36Sopenharmony_ci}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ciTEST_F(precedence, trace_is_fourth)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	pid_t parent;
141162306a36Sopenharmony_ci	long ret;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	parent = getppid();
141462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
141562306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
141862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
141962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
142062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
142162306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
142262306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
142362306a36Sopenharmony_ci	/* Should work just fine. */
142462306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
142562306a36Sopenharmony_ci	/* No ptracer */
142662306a36Sopenharmony_ci	EXPECT_EQ(-1, syscall(__NR_getpid));
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ciTEST_F(precedence, trace_is_fourth_in_any_order)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	pid_t parent;
143262306a36Sopenharmony_ci	long ret;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	parent = getppid();
143562306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
143662306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
143962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
144062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
144162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
144262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
144362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
144462306a36Sopenharmony_ci	/* Should work just fine. */
144562306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
144662306a36Sopenharmony_ci	/* No ptracer */
144762306a36Sopenharmony_ci	EXPECT_EQ(-1, syscall(__NR_getpid));
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ciTEST_F(precedence, log_is_fifth)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	pid_t mypid, parent;
145362306a36Sopenharmony_ci	long ret;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	mypid = getpid();
145662306a36Sopenharmony_ci	parent = getppid();
145762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
145862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
146162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
146262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
146362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
146462306a36Sopenharmony_ci	/* Should work just fine. */
146562306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
146662306a36Sopenharmony_ci	/* Should also work just fine */
146762306a36Sopenharmony_ci	EXPECT_EQ(mypid, syscall(__NR_getpid));
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ciTEST_F(precedence, log_is_fifth_in_any_order)
147162306a36Sopenharmony_ci{
147262306a36Sopenharmony_ci	pid_t mypid, parent;
147362306a36Sopenharmony_ci	long ret;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	mypid = getpid();
147662306a36Sopenharmony_ci	parent = getppid();
147762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
147862306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
148162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
148262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
148362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
148462306a36Sopenharmony_ci	/* Should work just fine. */
148562306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
148662306a36Sopenharmony_ci	/* Should also work just fine */
148762306a36Sopenharmony_ci	EXPECT_EQ(mypid, syscall(__NR_getpid));
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci#ifndef PTRACE_O_TRACESECCOMP
149162306a36Sopenharmony_ci#define PTRACE_O_TRACESECCOMP	0x00000080
149262306a36Sopenharmony_ci#endif
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci/* Catch the Ubuntu 12.04 value error. */
149562306a36Sopenharmony_ci#if PTRACE_EVENT_SECCOMP != 7
149662306a36Sopenharmony_ci#undef PTRACE_EVENT_SECCOMP
149762306a36Sopenharmony_ci#endif
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci#ifndef PTRACE_EVENT_SECCOMP
150062306a36Sopenharmony_ci#define PTRACE_EVENT_SECCOMP 7
150162306a36Sopenharmony_ci#endif
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci#define PTRACE_EVENT_MASK(status) ((status) >> 16)
150462306a36Sopenharmony_cibool tracer_running;
150562306a36Sopenharmony_civoid tracer_stop(int sig)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	tracer_running = false;
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_citypedef void tracer_func_t(struct __test_metadata *_metadata,
151162306a36Sopenharmony_ci			   pid_t tracee, int status, void *args);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_civoid start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
151462306a36Sopenharmony_ci	    tracer_func_t tracer_func, void *args, bool ptrace_syscall)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	int ret = -1;
151762306a36Sopenharmony_ci	struct sigaction action = {
151862306a36Sopenharmony_ci		.sa_handler = tracer_stop,
151962306a36Sopenharmony_ci	};
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/* Allow external shutdown. */
152262306a36Sopenharmony_ci	tracer_running = true;
152362306a36Sopenharmony_ci	ASSERT_EQ(0, sigaction(SIGUSR1, &action, NULL));
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	errno = 0;
152662306a36Sopenharmony_ci	while (ret == -1 && errno != EINVAL)
152762306a36Sopenharmony_ci		ret = ptrace(PTRACE_ATTACH, tracee, NULL, 0);
152862306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
152962306a36Sopenharmony_ci		kill(tracee, SIGKILL);
153062306a36Sopenharmony_ci	}
153162306a36Sopenharmony_ci	/* Wait for attach stop */
153262306a36Sopenharmony_ci	wait(NULL);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	ret = ptrace(PTRACE_SETOPTIONS, tracee, NULL, ptrace_syscall ?
153562306a36Sopenharmony_ci						      PTRACE_O_TRACESYSGOOD :
153662306a36Sopenharmony_ci						      PTRACE_O_TRACESECCOMP);
153762306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
153862306a36Sopenharmony_ci		TH_LOG("Failed to set PTRACE_O_TRACESECCOMP");
153962306a36Sopenharmony_ci		kill(tracee, SIGKILL);
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci	ret = ptrace(ptrace_syscall ? PTRACE_SYSCALL : PTRACE_CONT,
154262306a36Sopenharmony_ci		     tracee, NULL, 0);
154362306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	/* Unblock the tracee */
154662306a36Sopenharmony_ci	ASSERT_EQ(1, write(fd, "A", 1));
154762306a36Sopenharmony_ci	ASSERT_EQ(0, close(fd));
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/* Run until we're shut down. Must assert to stop execution. */
155062306a36Sopenharmony_ci	while (tracer_running) {
155162306a36Sopenharmony_ci		int status;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		if (wait(&status) != tracee)
155462306a36Sopenharmony_ci			continue;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci		if (WIFSIGNALED(status)) {
155762306a36Sopenharmony_ci			/* Child caught a fatal signal. */
155862306a36Sopenharmony_ci			return;
155962306a36Sopenharmony_ci		}
156062306a36Sopenharmony_ci		if (WIFEXITED(status)) {
156162306a36Sopenharmony_ci			/* Child exited with code. */
156262306a36Sopenharmony_ci			return;
156362306a36Sopenharmony_ci		}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci		/* Check if we got an expected event. */
156662306a36Sopenharmony_ci		ASSERT_EQ(WIFCONTINUED(status), false);
156762306a36Sopenharmony_ci		ASSERT_EQ(WIFSTOPPED(status), true);
156862306a36Sopenharmony_ci		ASSERT_EQ(WSTOPSIG(status) & SIGTRAP, SIGTRAP) {
156962306a36Sopenharmony_ci			TH_LOG("Unexpected WSTOPSIG: %d", WSTOPSIG(status));
157062306a36Sopenharmony_ci		}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		tracer_func(_metadata, tracee, status, args);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		ret = ptrace(ptrace_syscall ? PTRACE_SYSCALL : PTRACE_CONT,
157562306a36Sopenharmony_ci			     tracee, NULL, 0);
157662306a36Sopenharmony_ci		ASSERT_EQ(0, ret);
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci	/* Directly report the status of our test harness results. */
157962306a36Sopenharmony_ci	syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci/* Common tracer setup/teardown functions. */
158362306a36Sopenharmony_civoid cont_handler(int num)
158462306a36Sopenharmony_ci{ }
158562306a36Sopenharmony_cipid_t setup_trace_fixture(struct __test_metadata *_metadata,
158662306a36Sopenharmony_ci			  tracer_func_t func, void *args, bool ptrace_syscall)
158762306a36Sopenharmony_ci{
158862306a36Sopenharmony_ci	char sync;
158962306a36Sopenharmony_ci	int pipefd[2];
159062306a36Sopenharmony_ci	pid_t tracer_pid;
159162306a36Sopenharmony_ci	pid_t tracee = getpid();
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	/* Setup a pipe for clean synchronization. */
159462306a36Sopenharmony_ci	ASSERT_EQ(0, pipe(pipefd));
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	/* Fork a child which we'll promote to tracer */
159762306a36Sopenharmony_ci	tracer_pid = fork();
159862306a36Sopenharmony_ci	ASSERT_LE(0, tracer_pid);
159962306a36Sopenharmony_ci	signal(SIGALRM, cont_handler);
160062306a36Sopenharmony_ci	if (tracer_pid == 0) {
160162306a36Sopenharmony_ci		close(pipefd[0]);
160262306a36Sopenharmony_ci		start_tracer(_metadata, pipefd[1], tracee, func, args,
160362306a36Sopenharmony_ci			     ptrace_syscall);
160462306a36Sopenharmony_ci		syscall(__NR_exit, 0);
160562306a36Sopenharmony_ci	}
160662306a36Sopenharmony_ci	close(pipefd[1]);
160762306a36Sopenharmony_ci	prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0);
160862306a36Sopenharmony_ci	read(pipefd[0], &sync, 1);
160962306a36Sopenharmony_ci	close(pipefd[0]);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	return tracer_pid;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_civoid teardown_trace_fixture(struct __test_metadata *_metadata,
161562306a36Sopenharmony_ci			    pid_t tracer)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	if (tracer) {
161862306a36Sopenharmony_ci		int status;
161962306a36Sopenharmony_ci		/*
162062306a36Sopenharmony_ci		 * Extract the exit code from the other process and
162162306a36Sopenharmony_ci		 * adopt it for ourselves in case its asserts failed.
162262306a36Sopenharmony_ci		 */
162362306a36Sopenharmony_ci		ASSERT_EQ(0, kill(tracer, SIGUSR1));
162462306a36Sopenharmony_ci		ASSERT_EQ(tracer, waitpid(tracer, &status, 0));
162562306a36Sopenharmony_ci		if (WEXITSTATUS(status))
162662306a36Sopenharmony_ci			_metadata->passed = 0;
162762306a36Sopenharmony_ci	}
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci/* "poke" tracer arguments and function. */
163162306a36Sopenharmony_cistruct tracer_args_poke_t {
163262306a36Sopenharmony_ci	unsigned long poke_addr;
163362306a36Sopenharmony_ci};
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_civoid tracer_poke(struct __test_metadata *_metadata, pid_t tracee, int status,
163662306a36Sopenharmony_ci		 void *args)
163762306a36Sopenharmony_ci{
163862306a36Sopenharmony_ci	int ret;
163962306a36Sopenharmony_ci	unsigned long msg;
164062306a36Sopenharmony_ci	struct tracer_args_poke_t *info = (struct tracer_args_poke_t *)args;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
164362306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
164462306a36Sopenharmony_ci	/* If this fails, don't try to recover. */
164562306a36Sopenharmony_ci	ASSERT_EQ(0x1001, msg) {
164662306a36Sopenharmony_ci		kill(tracee, SIGKILL);
164762306a36Sopenharmony_ci	}
164862306a36Sopenharmony_ci	/*
164962306a36Sopenharmony_ci	 * Poke in the message.
165062306a36Sopenharmony_ci	 * Registers are not touched to try to keep this relatively arch
165162306a36Sopenharmony_ci	 * agnostic.
165262306a36Sopenharmony_ci	 */
165362306a36Sopenharmony_ci	ret = ptrace(PTRACE_POKEDATA, tracee, info->poke_addr, 0x1001);
165462306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
165562306a36Sopenharmony_ci}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ciFIXTURE(TRACE_poke) {
165862306a36Sopenharmony_ci	struct sock_fprog prog;
165962306a36Sopenharmony_ci	pid_t tracer;
166062306a36Sopenharmony_ci	long poked;
166162306a36Sopenharmony_ci	struct tracer_args_poke_t tracer_args;
166262306a36Sopenharmony_ci};
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ciFIXTURE_SETUP(TRACE_poke)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct sock_filter filter[] = {
166762306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
166862306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
166962306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),
167062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1001),
167162306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
167262306a36Sopenharmony_ci	};
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	self->poked = 0;
167562306a36Sopenharmony_ci	memset(&self->prog, 0, sizeof(self->prog));
167662306a36Sopenharmony_ci	self->prog.filter = malloc(sizeof(filter));
167762306a36Sopenharmony_ci	ASSERT_NE(NULL, self->prog.filter);
167862306a36Sopenharmony_ci	memcpy(self->prog.filter, filter, sizeof(filter));
167962306a36Sopenharmony_ci	self->prog.len = (unsigned short)ARRAY_SIZE(filter);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* Set up tracer args. */
168262306a36Sopenharmony_ci	self->tracer_args.poke_addr = (unsigned long)&self->poked;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	/* Launch tracer. */
168562306a36Sopenharmony_ci	self->tracer = setup_trace_fixture(_metadata, tracer_poke,
168662306a36Sopenharmony_ci					   &self->tracer_args, false);
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ciFIXTURE_TEARDOWN(TRACE_poke)
169062306a36Sopenharmony_ci{
169162306a36Sopenharmony_ci	teardown_trace_fixture(_metadata, self->tracer);
169262306a36Sopenharmony_ci	if (self->prog.filter)
169362306a36Sopenharmony_ci		free(self->prog.filter);
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ciTEST_F(TRACE_poke, read_has_side_effects)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	ssize_t ret;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
170162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
170462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	EXPECT_EQ(0, self->poked);
170762306a36Sopenharmony_ci	ret = read(-1, NULL, 0);
170862306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
170962306a36Sopenharmony_ci	EXPECT_EQ(0x1001, self->poked);
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ciTEST_F(TRACE_poke, getpid_runs_normally)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	long ret;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
171762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
172062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	EXPECT_EQ(0, self->poked);
172362306a36Sopenharmony_ci	EXPECT_NE(0, syscall(__NR_getpid));
172462306a36Sopenharmony_ci	EXPECT_EQ(0, self->poked);
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci#if defined(__x86_64__)
172862306a36Sopenharmony_ci# define ARCH_REGS		struct user_regs_struct
172962306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).orig_rax
173062306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).rax
173162306a36Sopenharmony_ci#elif defined(__i386__)
173262306a36Sopenharmony_ci# define ARCH_REGS		struct user_regs_struct
173362306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).orig_eax
173462306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).eax
173562306a36Sopenharmony_ci#elif defined(__arm__)
173662306a36Sopenharmony_ci# define ARCH_REGS		struct pt_regs
173762306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).ARM_r7
173862306a36Sopenharmony_ci# ifndef PTRACE_SET_SYSCALL
173962306a36Sopenharmony_ci#  define PTRACE_SET_SYSCALL   23
174062306a36Sopenharmony_ci# endif
174162306a36Sopenharmony_ci# define SYSCALL_NUM_SET(_regs, _nr)	\
174262306a36Sopenharmony_ci		EXPECT_EQ(0, ptrace(PTRACE_SET_SYSCALL, tracee, NULL, _nr))
174362306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).ARM_r0
174462306a36Sopenharmony_ci#elif defined(__aarch64__)
174562306a36Sopenharmony_ci# define ARCH_REGS		struct user_pt_regs
174662306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).regs[8]
174762306a36Sopenharmony_ci# ifndef NT_ARM_SYSTEM_CALL
174862306a36Sopenharmony_ci#  define NT_ARM_SYSTEM_CALL 0x404
174962306a36Sopenharmony_ci# endif
175062306a36Sopenharmony_ci# define SYSCALL_NUM_SET(_regs, _nr)				\
175162306a36Sopenharmony_ci	do {							\
175262306a36Sopenharmony_ci		struct iovec __v;				\
175362306a36Sopenharmony_ci		typeof(_nr) __nr = (_nr);			\
175462306a36Sopenharmony_ci		__v.iov_base = &__nr;				\
175562306a36Sopenharmony_ci		__v.iov_len = sizeof(__nr);			\
175662306a36Sopenharmony_ci		EXPECT_EQ(0, ptrace(PTRACE_SETREGSET, tracee,	\
175762306a36Sopenharmony_ci				    NT_ARM_SYSTEM_CALL, &__v));	\
175862306a36Sopenharmony_ci	} while (0)
175962306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).regs[0]
176062306a36Sopenharmony_ci#elif defined(__loongarch__)
176162306a36Sopenharmony_ci# define ARCH_REGS		struct user_pt_regs
176262306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).regs[11]
176362306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).regs[4]
176462306a36Sopenharmony_ci#elif defined(__riscv) && __riscv_xlen == 64
176562306a36Sopenharmony_ci# define ARCH_REGS		struct user_regs_struct
176662306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).a7
176762306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).a0
176862306a36Sopenharmony_ci#elif defined(__csky__)
176962306a36Sopenharmony_ci# define ARCH_REGS		struct pt_regs
177062306a36Sopenharmony_ci#  if defined(__CSKYABIV2__)
177162306a36Sopenharmony_ci#   define SYSCALL_NUM(_regs)	(_regs).regs[3]
177262306a36Sopenharmony_ci#  else
177362306a36Sopenharmony_ci#   define SYSCALL_NUM(_regs)	(_regs).regs[9]
177462306a36Sopenharmony_ci#  endif
177562306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).a0
177662306a36Sopenharmony_ci#elif defined(__hppa__)
177762306a36Sopenharmony_ci# define ARCH_REGS		struct user_regs_struct
177862306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).gr[20]
177962306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).gr[28]
178062306a36Sopenharmony_ci#elif defined(__powerpc__)
178162306a36Sopenharmony_ci# define ARCH_REGS		struct pt_regs
178262306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).gpr[0]
178362306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).gpr[3]
178462306a36Sopenharmony_ci# define SYSCALL_RET_SET(_regs, _val)				\
178562306a36Sopenharmony_ci	do {							\
178662306a36Sopenharmony_ci		typeof(_val) _result = (_val);			\
178762306a36Sopenharmony_ci		if ((_regs.trap & 0xfff0) == 0x3000) {		\
178862306a36Sopenharmony_ci			/*					\
178962306a36Sopenharmony_ci			 * scv 0 system call uses -ve result	\
179062306a36Sopenharmony_ci			 * for error, so no need to adjust.	\
179162306a36Sopenharmony_ci			 */					\
179262306a36Sopenharmony_ci			SYSCALL_RET(_regs) = _result;		\
179362306a36Sopenharmony_ci		} else {					\
179462306a36Sopenharmony_ci			/*					\
179562306a36Sopenharmony_ci			 * A syscall error is signaled by the	\
179662306a36Sopenharmony_ci			 * CR0 SO bit and the code is stored as	\
179762306a36Sopenharmony_ci			 * a positive value.			\
179862306a36Sopenharmony_ci			 */					\
179962306a36Sopenharmony_ci			if (_result < 0) {			\
180062306a36Sopenharmony_ci				SYSCALL_RET(_regs) = -_result;	\
180162306a36Sopenharmony_ci				(_regs).ccr |= 0x10000000;	\
180262306a36Sopenharmony_ci			} else {				\
180362306a36Sopenharmony_ci				SYSCALL_RET(_regs) = _result;	\
180462306a36Sopenharmony_ci				(_regs).ccr &= ~0x10000000;	\
180562306a36Sopenharmony_ci			}					\
180662306a36Sopenharmony_ci		}						\
180762306a36Sopenharmony_ci	} while (0)
180862306a36Sopenharmony_ci# define SYSCALL_RET_SET_ON_PTRACE_EXIT
180962306a36Sopenharmony_ci#elif defined(__s390__)
181062306a36Sopenharmony_ci# define ARCH_REGS		s390_regs
181162306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).gprs[2]
181262306a36Sopenharmony_ci# define SYSCALL_RET_SET(_regs, _val)			\
181362306a36Sopenharmony_ci		TH_LOG("Can't modify syscall return on this architecture")
181462306a36Sopenharmony_ci#elif defined(__mips__)
181562306a36Sopenharmony_ci# include <asm/unistd_nr_n32.h>
181662306a36Sopenharmony_ci# include <asm/unistd_nr_n64.h>
181762306a36Sopenharmony_ci# include <asm/unistd_nr_o32.h>
181862306a36Sopenharmony_ci# define ARCH_REGS		struct pt_regs
181962306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)				\
182062306a36Sopenharmony_ci	({						\
182162306a36Sopenharmony_ci		typeof((_regs).regs[2]) _nr;		\
182262306a36Sopenharmony_ci		if ((_regs).regs[2] == __NR_O32_Linux)	\
182362306a36Sopenharmony_ci			_nr = (_regs).regs[4];		\
182462306a36Sopenharmony_ci		else					\
182562306a36Sopenharmony_ci			_nr = (_regs).regs[2];		\
182662306a36Sopenharmony_ci		_nr;					\
182762306a36Sopenharmony_ci	})
182862306a36Sopenharmony_ci# define SYSCALL_NUM_SET(_regs, _nr)			\
182962306a36Sopenharmony_ci	do {						\
183062306a36Sopenharmony_ci		if ((_regs).regs[2] == __NR_O32_Linux)	\
183162306a36Sopenharmony_ci			(_regs).regs[4] = _nr;		\
183262306a36Sopenharmony_ci		else					\
183362306a36Sopenharmony_ci			(_regs).regs[2] = _nr;		\
183462306a36Sopenharmony_ci	} while (0)
183562306a36Sopenharmony_ci# define SYSCALL_RET_SET(_regs, _val)			\
183662306a36Sopenharmony_ci		TH_LOG("Can't modify syscall return on this architecture")
183762306a36Sopenharmony_ci#elif defined(__xtensa__)
183862306a36Sopenharmony_ci# define ARCH_REGS		struct user_pt_regs
183962306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).syscall
184062306a36Sopenharmony_ci/*
184162306a36Sopenharmony_ci * On xtensa syscall return value is in the register
184262306a36Sopenharmony_ci * a2 of the current window which is not fixed.
184362306a36Sopenharmony_ci */
184462306a36Sopenharmony_ci#define SYSCALL_RET(_regs)	(_regs).a[(_regs).windowbase * 4 + 2]
184562306a36Sopenharmony_ci#elif defined(__sh__)
184662306a36Sopenharmony_ci# define ARCH_REGS		struct pt_regs
184762306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).regs[3]
184862306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).regs[0]
184962306a36Sopenharmony_ci#elif defined(__mc68000__)
185062306a36Sopenharmony_ci# define ARCH_REGS		struct user_regs_struct
185162306a36Sopenharmony_ci# define SYSCALL_NUM(_regs)	(_regs).orig_d0
185262306a36Sopenharmony_ci# define SYSCALL_RET(_regs)	(_regs).d0
185362306a36Sopenharmony_ci#else
185462306a36Sopenharmony_ci# error "Do not know how to find your architecture's registers and syscalls"
185562306a36Sopenharmony_ci#endif
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci/*
185862306a36Sopenharmony_ci * Most architectures can change the syscall by just updating the
185962306a36Sopenharmony_ci * associated register. This is the default if not defined above.
186062306a36Sopenharmony_ci */
186162306a36Sopenharmony_ci#ifndef SYSCALL_NUM_SET
186262306a36Sopenharmony_ci# define SYSCALL_NUM_SET(_regs, _nr)		\
186362306a36Sopenharmony_ci	do {					\
186462306a36Sopenharmony_ci		SYSCALL_NUM(_regs) = (_nr);	\
186562306a36Sopenharmony_ci	} while (0)
186662306a36Sopenharmony_ci#endif
186762306a36Sopenharmony_ci/*
186862306a36Sopenharmony_ci * Most architectures can change the syscall return value by just
186962306a36Sopenharmony_ci * writing to the SYSCALL_RET register. This is the default if not
187062306a36Sopenharmony_ci * defined above. If an architecture cannot set the return value
187162306a36Sopenharmony_ci * (for example when the syscall and return value register is
187262306a36Sopenharmony_ci * shared), report it with TH_LOG() in an arch-specific definition
187362306a36Sopenharmony_ci * of SYSCALL_RET_SET() above, and leave SYSCALL_RET undefined.
187462306a36Sopenharmony_ci */
187562306a36Sopenharmony_ci#if !defined(SYSCALL_RET) && !defined(SYSCALL_RET_SET)
187662306a36Sopenharmony_ci# error "One of SYSCALL_RET or SYSCALL_RET_SET is needed for this arch"
187762306a36Sopenharmony_ci#endif
187862306a36Sopenharmony_ci#ifndef SYSCALL_RET_SET
187962306a36Sopenharmony_ci# define SYSCALL_RET_SET(_regs, _val)		\
188062306a36Sopenharmony_ci	do {					\
188162306a36Sopenharmony_ci		SYSCALL_RET(_regs) = (_val);	\
188262306a36Sopenharmony_ci	} while (0)
188362306a36Sopenharmony_ci#endif
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci/* When the syscall return can't be changed, stub out the tests for it. */
188662306a36Sopenharmony_ci#ifndef SYSCALL_RET
188762306a36Sopenharmony_ci# define EXPECT_SYSCALL_RETURN(val, action)	EXPECT_EQ(-1, action)
188862306a36Sopenharmony_ci#else
188962306a36Sopenharmony_ci# define EXPECT_SYSCALL_RETURN(val, action)		\
189062306a36Sopenharmony_ci	do {						\
189162306a36Sopenharmony_ci		errno = 0;				\
189262306a36Sopenharmony_ci		if (val < 0) {				\
189362306a36Sopenharmony_ci			EXPECT_EQ(-1, action);		\
189462306a36Sopenharmony_ci			EXPECT_EQ(-(val), errno);	\
189562306a36Sopenharmony_ci		} else {				\
189662306a36Sopenharmony_ci			EXPECT_EQ(val, action);		\
189762306a36Sopenharmony_ci		}					\
189862306a36Sopenharmony_ci	} while (0)
189962306a36Sopenharmony_ci#endif
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci/*
190262306a36Sopenharmony_ci * Some architectures (e.g. powerpc) can only set syscall
190362306a36Sopenharmony_ci * return values on syscall exit during ptrace.
190462306a36Sopenharmony_ci */
190562306a36Sopenharmony_ciconst bool ptrace_entry_set_syscall_nr = true;
190662306a36Sopenharmony_ciconst bool ptrace_entry_set_syscall_ret =
190762306a36Sopenharmony_ci#ifndef SYSCALL_RET_SET_ON_PTRACE_EXIT
190862306a36Sopenharmony_ci	true;
190962306a36Sopenharmony_ci#else
191062306a36Sopenharmony_ci	false;
191162306a36Sopenharmony_ci#endif
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci/*
191462306a36Sopenharmony_ci * Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
191562306a36Sopenharmony_ci * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).
191662306a36Sopenharmony_ci */
191762306a36Sopenharmony_ci#if defined(__x86_64__) || defined(__i386__) || defined(__mips__) || defined(__mc68000__)
191862306a36Sopenharmony_ci# define ARCH_GETREGS(_regs)	ptrace(PTRACE_GETREGS, tracee, 0, &(_regs))
191962306a36Sopenharmony_ci# define ARCH_SETREGS(_regs)	ptrace(PTRACE_SETREGS, tracee, 0, &(_regs))
192062306a36Sopenharmony_ci#else
192162306a36Sopenharmony_ci# define ARCH_GETREGS(_regs)	({					\
192262306a36Sopenharmony_ci		struct iovec __v;					\
192362306a36Sopenharmony_ci		__v.iov_base = &(_regs);				\
192462306a36Sopenharmony_ci		__v.iov_len = sizeof(_regs);				\
192562306a36Sopenharmony_ci		ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &__v);	\
192662306a36Sopenharmony_ci	})
192762306a36Sopenharmony_ci# define ARCH_SETREGS(_regs)	({					\
192862306a36Sopenharmony_ci		struct iovec __v;					\
192962306a36Sopenharmony_ci		__v.iov_base = &(_regs);				\
193062306a36Sopenharmony_ci		__v.iov_len = sizeof(_regs);				\
193162306a36Sopenharmony_ci		ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &__v);	\
193262306a36Sopenharmony_ci	})
193362306a36Sopenharmony_ci#endif
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci/* Architecture-specific syscall fetching routine. */
193662306a36Sopenharmony_ciint get_syscall(struct __test_metadata *_metadata, pid_t tracee)
193762306a36Sopenharmony_ci{
193862306a36Sopenharmony_ci	ARCH_REGS regs;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	EXPECT_EQ(0, ARCH_GETREGS(regs)) {
194162306a36Sopenharmony_ci		return -1;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	return SYSCALL_NUM(regs);
194562306a36Sopenharmony_ci}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci/* Architecture-specific syscall changing routine. */
194862306a36Sopenharmony_civoid __change_syscall(struct __test_metadata *_metadata,
194962306a36Sopenharmony_ci		    pid_t tracee, long *syscall, long *ret)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	ARCH_REGS orig, regs;
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	/* Do not get/set registers if we have nothing to do. */
195462306a36Sopenharmony_ci	if (!syscall && !ret)
195562306a36Sopenharmony_ci		return;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	EXPECT_EQ(0, ARCH_GETREGS(regs)) {
195862306a36Sopenharmony_ci		return;
195962306a36Sopenharmony_ci	}
196062306a36Sopenharmony_ci	orig = regs;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	if (syscall)
196362306a36Sopenharmony_ci		SYSCALL_NUM_SET(regs, *syscall);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (ret)
196662306a36Sopenharmony_ci		SYSCALL_RET_SET(regs, *ret);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	/* Flush any register changes made. */
196962306a36Sopenharmony_ci	if (memcmp(&orig, &regs, sizeof(orig)) != 0)
197062306a36Sopenharmony_ci		EXPECT_EQ(0, ARCH_SETREGS(regs));
197162306a36Sopenharmony_ci}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci/* Change only syscall number. */
197462306a36Sopenharmony_civoid change_syscall_nr(struct __test_metadata *_metadata,
197562306a36Sopenharmony_ci		       pid_t tracee, long syscall)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	__change_syscall(_metadata, tracee, &syscall, NULL);
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci/* Change syscall return value (and set syscall number to -1). */
198162306a36Sopenharmony_civoid change_syscall_ret(struct __test_metadata *_metadata,
198262306a36Sopenharmony_ci			pid_t tracee, long ret)
198362306a36Sopenharmony_ci{
198462306a36Sopenharmony_ci	long syscall = -1;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	__change_syscall(_metadata, tracee, &syscall, &ret);
198762306a36Sopenharmony_ci}
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_civoid tracer_seccomp(struct __test_metadata *_metadata, pid_t tracee,
199062306a36Sopenharmony_ci		    int status, void *args)
199162306a36Sopenharmony_ci{
199262306a36Sopenharmony_ci	int ret;
199362306a36Sopenharmony_ci	unsigned long msg;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	EXPECT_EQ(PTRACE_EVENT_MASK(status), PTRACE_EVENT_SECCOMP) {
199662306a36Sopenharmony_ci		TH_LOG("Unexpected ptrace event: %d", PTRACE_EVENT_MASK(status));
199762306a36Sopenharmony_ci		return;
199862306a36Sopenharmony_ci	}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	/* Make sure we got the right message. */
200162306a36Sopenharmony_ci	ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
200262306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	/* Validate and take action on expected syscalls. */
200562306a36Sopenharmony_ci	switch (msg) {
200662306a36Sopenharmony_ci	case 0x1002:
200762306a36Sopenharmony_ci		/* change getpid to getppid. */
200862306a36Sopenharmony_ci		EXPECT_EQ(__NR_getpid, get_syscall(_metadata, tracee));
200962306a36Sopenharmony_ci		change_syscall_nr(_metadata, tracee, __NR_getppid);
201062306a36Sopenharmony_ci		break;
201162306a36Sopenharmony_ci	case 0x1003:
201262306a36Sopenharmony_ci		/* skip gettid with valid return code. */
201362306a36Sopenharmony_ci		EXPECT_EQ(__NR_gettid, get_syscall(_metadata, tracee));
201462306a36Sopenharmony_ci		change_syscall_ret(_metadata, tracee, 45000);
201562306a36Sopenharmony_ci		break;
201662306a36Sopenharmony_ci	case 0x1004:
201762306a36Sopenharmony_ci		/* skip openat with error. */
201862306a36Sopenharmony_ci		EXPECT_EQ(__NR_openat, get_syscall(_metadata, tracee));
201962306a36Sopenharmony_ci		change_syscall_ret(_metadata, tracee, -ESRCH);
202062306a36Sopenharmony_ci		break;
202162306a36Sopenharmony_ci	case 0x1005:
202262306a36Sopenharmony_ci		/* do nothing (allow getppid) */
202362306a36Sopenharmony_ci		EXPECT_EQ(__NR_getppid, get_syscall(_metadata, tracee));
202462306a36Sopenharmony_ci		break;
202562306a36Sopenharmony_ci	default:
202662306a36Sopenharmony_ci		EXPECT_EQ(0, msg) {
202762306a36Sopenharmony_ci			TH_LOG("Unknown PTRACE_GETEVENTMSG: 0x%lx", msg);
202862306a36Sopenharmony_ci			kill(tracee, SIGKILL);
202962306a36Sopenharmony_ci		}
203062306a36Sopenharmony_ci	}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ciFIXTURE(TRACE_syscall) {
203562306a36Sopenharmony_ci	struct sock_fprog prog;
203662306a36Sopenharmony_ci	pid_t tracer, mytid, mypid, parent;
203762306a36Sopenharmony_ci	long syscall_nr;
203862306a36Sopenharmony_ci};
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_civoid tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
204162306a36Sopenharmony_ci		   int status, void *args)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	int ret;
204462306a36Sopenharmony_ci	unsigned long msg;
204562306a36Sopenharmony_ci	static bool entry;
204662306a36Sopenharmony_ci	long syscall_nr_val, syscall_ret_val;
204762306a36Sopenharmony_ci	long *syscall_nr = NULL, *syscall_ret = NULL;
204862306a36Sopenharmony_ci	FIXTURE_DATA(TRACE_syscall) *self = args;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	EXPECT_EQ(WSTOPSIG(status) & 0x80, 0x80) {
205162306a36Sopenharmony_ci		TH_LOG("Unexpected WSTOPSIG: %d", WSTOPSIG(status));
205262306a36Sopenharmony_ci		return;
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	/*
205662306a36Sopenharmony_ci	 * The traditional way to tell PTRACE_SYSCALL entry/exit
205762306a36Sopenharmony_ci	 * is by counting.
205862306a36Sopenharmony_ci	 */
205962306a36Sopenharmony_ci	entry = !entry;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	/* Make sure we got an appropriate message. */
206262306a36Sopenharmony_ci	ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
206362306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
206462306a36Sopenharmony_ci	EXPECT_EQ(entry ? PTRACE_EVENTMSG_SYSCALL_ENTRY
206562306a36Sopenharmony_ci			: PTRACE_EVENTMSG_SYSCALL_EXIT, msg);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	/*
206862306a36Sopenharmony_ci	 * Some architectures only support setting return values during
206962306a36Sopenharmony_ci	 * syscall exit under ptrace, and on exit the syscall number may
207062306a36Sopenharmony_ci	 * no longer be available. Therefore, save the initial sycall
207162306a36Sopenharmony_ci	 * number here, so it can be examined during both entry and exit
207262306a36Sopenharmony_ci	 * phases.
207362306a36Sopenharmony_ci	 */
207462306a36Sopenharmony_ci	if (entry)
207562306a36Sopenharmony_ci		self->syscall_nr = get_syscall(_metadata, tracee);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	/*
207862306a36Sopenharmony_ci	 * Depending on the architecture's syscall setting abilities, we
207962306a36Sopenharmony_ci	 * pick which things to set during this phase (entry or exit).
208062306a36Sopenharmony_ci	 */
208162306a36Sopenharmony_ci	if (entry == ptrace_entry_set_syscall_nr)
208262306a36Sopenharmony_ci		syscall_nr = &syscall_nr_val;
208362306a36Sopenharmony_ci	if (entry == ptrace_entry_set_syscall_ret)
208462306a36Sopenharmony_ci		syscall_ret = &syscall_ret_val;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	/* Now handle the actual rewriting cases. */
208762306a36Sopenharmony_ci	switch (self->syscall_nr) {
208862306a36Sopenharmony_ci	case __NR_getpid:
208962306a36Sopenharmony_ci		syscall_nr_val = __NR_getppid;
209062306a36Sopenharmony_ci		/* Never change syscall return for this case. */
209162306a36Sopenharmony_ci		syscall_ret = NULL;
209262306a36Sopenharmony_ci		break;
209362306a36Sopenharmony_ci	case __NR_gettid:
209462306a36Sopenharmony_ci		syscall_nr_val = -1;
209562306a36Sopenharmony_ci		syscall_ret_val = 45000;
209662306a36Sopenharmony_ci		break;
209762306a36Sopenharmony_ci	case __NR_openat:
209862306a36Sopenharmony_ci		syscall_nr_val = -1;
209962306a36Sopenharmony_ci		syscall_ret_val = -ESRCH;
210062306a36Sopenharmony_ci		break;
210162306a36Sopenharmony_ci	default:
210262306a36Sopenharmony_ci		/* Unhandled, do nothing. */
210362306a36Sopenharmony_ci		return;
210462306a36Sopenharmony_ci	}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	__change_syscall(_metadata, tracee, syscall_nr, syscall_ret);
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ciFIXTURE_VARIANT(TRACE_syscall) {
211062306a36Sopenharmony_ci	/*
211162306a36Sopenharmony_ci	 * All of the SECCOMP_RET_TRACE behaviors can be tested with either
211262306a36Sopenharmony_ci	 * SECCOMP_RET_TRACE+PTRACE_CONT or plain ptrace()+PTRACE_SYSCALL.
211362306a36Sopenharmony_ci	 * This indicates if we should use SECCOMP_RET_TRACE (false), or
211462306a36Sopenharmony_ci	 * ptrace (true).
211562306a36Sopenharmony_ci	 */
211662306a36Sopenharmony_ci	bool use_ptrace;
211762306a36Sopenharmony_ci};
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(TRACE_syscall, ptrace) {
212062306a36Sopenharmony_ci	.use_ptrace = true,
212162306a36Sopenharmony_ci};
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(TRACE_syscall, seccomp) {
212462306a36Sopenharmony_ci	.use_ptrace = false,
212562306a36Sopenharmony_ci};
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ciFIXTURE_SETUP(TRACE_syscall)
212862306a36Sopenharmony_ci{
212962306a36Sopenharmony_ci	struct sock_filter filter[] = {
213062306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
213162306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
213262306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
213362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1002),
213462306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_gettid, 0, 1),
213562306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1003),
213662306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_openat, 0, 1),
213762306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1004),
213862306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
213962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1005),
214062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
214162306a36Sopenharmony_ci	};
214262306a36Sopenharmony_ci	struct sock_fprog prog = {
214362306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
214462306a36Sopenharmony_ci		.filter = filter,
214562306a36Sopenharmony_ci	};
214662306a36Sopenharmony_ci	long ret;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	/* Prepare some testable syscall results. */
214962306a36Sopenharmony_ci	self->mytid = syscall(__NR_gettid);
215062306a36Sopenharmony_ci	ASSERT_GT(self->mytid, 0);
215162306a36Sopenharmony_ci	ASSERT_NE(self->mytid, 1) {
215262306a36Sopenharmony_ci		TH_LOG("Running this test as init is not supported. :)");
215362306a36Sopenharmony_ci	}
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	self->mypid = getpid();
215662306a36Sopenharmony_ci	ASSERT_GT(self->mypid, 0);
215762306a36Sopenharmony_ci	ASSERT_EQ(self->mytid, self->mypid);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	self->parent = getppid();
216062306a36Sopenharmony_ci	ASSERT_GT(self->parent, 0);
216162306a36Sopenharmony_ci	ASSERT_NE(self->parent, self->mypid);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	/* Launch tracer. */
216462306a36Sopenharmony_ci	self->tracer = setup_trace_fixture(_metadata,
216562306a36Sopenharmony_ci					   variant->use_ptrace ? tracer_ptrace
216662306a36Sopenharmony_ci							       : tracer_seccomp,
216762306a36Sopenharmony_ci					   self, variant->use_ptrace);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
217062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	/* Do not install seccomp rewrite filters, as we'll use ptrace instead. */
217362306a36Sopenharmony_ci	if (variant->use_ptrace)
217462306a36Sopenharmony_ci		return;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
217762306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ciFIXTURE_TEARDOWN(TRACE_syscall)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	teardown_trace_fixture(_metadata, self->tracer);
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ciTEST(negative_ENOSYS)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci#if defined(__arm__)
218862306a36Sopenharmony_ci	SKIP(return, "arm32 does not support calling syscall -1");
218962306a36Sopenharmony_ci#endif
219062306a36Sopenharmony_ci	/*
219162306a36Sopenharmony_ci	 * There should be no difference between an "internal" skip
219262306a36Sopenharmony_ci	 * and userspace asking for syscall "-1".
219362306a36Sopenharmony_ci	 */
219462306a36Sopenharmony_ci	errno = 0;
219562306a36Sopenharmony_ci	EXPECT_EQ(-1, syscall(-1));
219662306a36Sopenharmony_ci	EXPECT_EQ(errno, ENOSYS);
219762306a36Sopenharmony_ci	/* And no difference for "still not valid but not -1". */
219862306a36Sopenharmony_ci	errno = 0;
219962306a36Sopenharmony_ci	EXPECT_EQ(-1, syscall(-101));
220062306a36Sopenharmony_ci	EXPECT_EQ(errno, ENOSYS);
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ciTEST_F(TRACE_syscall, negative_ENOSYS)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	negative_ENOSYS(_metadata);
220662306a36Sopenharmony_ci}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ciTEST_F(TRACE_syscall, syscall_allowed)
220962306a36Sopenharmony_ci{
221062306a36Sopenharmony_ci	/* getppid works as expected (no changes). */
221162306a36Sopenharmony_ci	EXPECT_EQ(self->parent, syscall(__NR_getppid));
221262306a36Sopenharmony_ci	EXPECT_NE(self->mypid, syscall(__NR_getppid));
221362306a36Sopenharmony_ci}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ciTEST_F(TRACE_syscall, syscall_redirected)
221662306a36Sopenharmony_ci{
221762306a36Sopenharmony_ci	/* getpid has been redirected to getppid as expected. */
221862306a36Sopenharmony_ci	EXPECT_EQ(self->parent, syscall(__NR_getpid));
221962306a36Sopenharmony_ci	EXPECT_NE(self->mypid, syscall(__NR_getpid));
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ciTEST_F(TRACE_syscall, syscall_errno)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	/* Tracer should skip the open syscall, resulting in ESRCH. */
222562306a36Sopenharmony_ci	EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
222662306a36Sopenharmony_ci}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ciTEST_F(TRACE_syscall, syscall_faked)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	/* Tracer skips the gettid syscall and store altered return value. */
223162306a36Sopenharmony_ci	EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ciTEST_F_SIGNAL(TRACE_syscall, kill_immediate, SIGSYS)
223562306a36Sopenharmony_ci{
223662306a36Sopenharmony_ci	struct sock_filter filter[] = {
223762306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
223862306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
223962306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_mknodat, 0, 1),
224062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD),
224162306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
224262306a36Sopenharmony_ci	};
224362306a36Sopenharmony_ci	struct sock_fprog prog = {
224462306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
224562306a36Sopenharmony_ci		.filter = filter,
224662306a36Sopenharmony_ci	};
224762306a36Sopenharmony_ci	long ret;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	/* Install "kill on mknodat" filter. */
225062306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
225162306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	/* This should immediately die with SIGSYS, regardless of tracer. */
225462306a36Sopenharmony_ci	EXPECT_EQ(-1, syscall(__NR_mknodat, -1, NULL, 0, 0));
225562306a36Sopenharmony_ci}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ciTEST_F(TRACE_syscall, skip_after)
225862306a36Sopenharmony_ci{
225962306a36Sopenharmony_ci	struct sock_filter filter[] = {
226062306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
226162306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
226262306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
226362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | EPERM),
226462306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
226562306a36Sopenharmony_ci	};
226662306a36Sopenharmony_ci	struct sock_fprog prog = {
226762306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
226862306a36Sopenharmony_ci		.filter = filter,
226962306a36Sopenharmony_ci	};
227062306a36Sopenharmony_ci	long ret;
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	/* Install additional "errno on getppid" filter. */
227362306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
227462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	/* Tracer will redirect getpid to getppid, and we should see EPERM. */
227762306a36Sopenharmony_ci	errno = 0;
227862306a36Sopenharmony_ci	EXPECT_EQ(-1, syscall(__NR_getpid));
227962306a36Sopenharmony_ci	EXPECT_EQ(EPERM, errno);
228062306a36Sopenharmony_ci}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ciTEST_F_SIGNAL(TRACE_syscall, kill_after, SIGSYS)
228362306a36Sopenharmony_ci{
228462306a36Sopenharmony_ci	struct sock_filter filter[] = {
228562306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
228662306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
228762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
228862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
228962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
229062306a36Sopenharmony_ci	};
229162306a36Sopenharmony_ci	struct sock_fprog prog = {
229262306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
229362306a36Sopenharmony_ci		.filter = filter,
229462306a36Sopenharmony_ci	};
229562306a36Sopenharmony_ci	long ret;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	/* Install additional "death on getppid" filter. */
229862306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
229962306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	/* Tracer will redirect getpid to getppid, and we should die. */
230262306a36Sopenharmony_ci	EXPECT_NE(self->mypid, syscall(__NR_getpid));
230362306a36Sopenharmony_ci}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ciTEST(seccomp_syscall)
230662306a36Sopenharmony_ci{
230762306a36Sopenharmony_ci	struct sock_filter filter[] = {
230862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
230962306a36Sopenharmony_ci	};
231062306a36Sopenharmony_ci	struct sock_fprog prog = {
231162306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
231262306a36Sopenharmony_ci		.filter = filter,
231362306a36Sopenharmony_ci	};
231462306a36Sopenharmony_ci	long ret;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
231762306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
231862306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
231962306a36Sopenharmony_ci	}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	/* Reject insane operation. */
232262306a36Sopenharmony_ci	ret = seccomp(-1, 0, &prog);
232362306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
232462306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
232762306a36Sopenharmony_ci		TH_LOG("Did not reject crazy op value!");
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	/* Reject strict with flags or pointer. */
233162306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_STRICT, -1, NULL);
233262306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
233362306a36Sopenharmony_ci		TH_LOG("Did not reject mode strict with flags!");
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, &prog);
233662306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
233762306a36Sopenharmony_ci		TH_LOG("Did not reject mode strict with uargs!");
233862306a36Sopenharmony_ci	}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	/* Reject insane args for filter. */
234162306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, -1, &prog);
234262306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
234362306a36Sopenharmony_ci		TH_LOG("Did not reject crazy filter flags!");
234462306a36Sopenharmony_ci	}
234562306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, NULL);
234662306a36Sopenharmony_ci	EXPECT_EQ(EFAULT, errno) {
234762306a36Sopenharmony_ci		TH_LOG("Did not reject NULL filter!");
234862306a36Sopenharmony_ci	}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
235162306a36Sopenharmony_ci	EXPECT_EQ(0, errno) {
235262306a36Sopenharmony_ci		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER: %s",
235362306a36Sopenharmony_ci			strerror(errno));
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ciTEST(seccomp_syscall_mode_lock)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct sock_filter filter[] = {
236062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
236162306a36Sopenharmony_ci	};
236262306a36Sopenharmony_ci	struct sock_fprog prog = {
236362306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
236462306a36Sopenharmony_ci		.filter = filter,
236562306a36Sopenharmony_ci	};
236662306a36Sopenharmony_ci	long ret;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
236962306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
237062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
237162306a36Sopenharmony_ci	}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
237462306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
237562306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci	EXPECT_EQ(0, ret) {
237862306a36Sopenharmony_ci		TH_LOG("Could not install filter!");
237962306a36Sopenharmony_ci	}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	/* Make sure neither entry point will switch to strict. */
238262306a36Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0);
238362306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
238462306a36Sopenharmony_ci		TH_LOG("Switched to mode strict!");
238562306a36Sopenharmony_ci	}
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL);
238862306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
238962306a36Sopenharmony_ci		TH_LOG("Switched to mode strict!");
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ci}
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci/*
239462306a36Sopenharmony_ci * Test detection of known and unknown filter flags. Userspace needs to be able
239562306a36Sopenharmony_ci * to check if a filter flag is supported by the current kernel and a good way
239662306a36Sopenharmony_ci * of doing that is by attempting to enter filter mode, with the flag bit in
239762306a36Sopenharmony_ci * question set, and a NULL pointer for the _args_ parameter. EFAULT indicates
239862306a36Sopenharmony_ci * that the flag is valid and EINVAL indicates that the flag is invalid.
239962306a36Sopenharmony_ci */
240062306a36Sopenharmony_ciTEST(detect_seccomp_filter_flags)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC,
240362306a36Sopenharmony_ci				 SECCOMP_FILTER_FLAG_LOG,
240462306a36Sopenharmony_ci				 SECCOMP_FILTER_FLAG_SPEC_ALLOW,
240562306a36Sopenharmony_ci				 SECCOMP_FILTER_FLAG_NEW_LISTENER,
240662306a36Sopenharmony_ci				 SECCOMP_FILTER_FLAG_TSYNC_ESRCH };
240762306a36Sopenharmony_ci	unsigned int exclusive[] = {
240862306a36Sopenharmony_ci				SECCOMP_FILTER_FLAG_TSYNC,
240962306a36Sopenharmony_ci				SECCOMP_FILTER_FLAG_NEW_LISTENER };
241062306a36Sopenharmony_ci	unsigned int flag, all_flags, exclusive_mask;
241162306a36Sopenharmony_ci	int i;
241262306a36Sopenharmony_ci	long ret;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	/* Test detection of individual known-good filter flags */
241562306a36Sopenharmony_ci	for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) {
241662306a36Sopenharmony_ci		int bits = 0;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci		flag = flags[i];
241962306a36Sopenharmony_ci		/* Make sure the flag is a single bit! */
242062306a36Sopenharmony_ci		while (flag) {
242162306a36Sopenharmony_ci			if (flag & 0x1)
242262306a36Sopenharmony_ci				bits ++;
242362306a36Sopenharmony_ci			flag >>= 1;
242462306a36Sopenharmony_ci		}
242562306a36Sopenharmony_ci		ASSERT_EQ(1, bits);
242662306a36Sopenharmony_ci		flag = flags[i];
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci		ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
242962306a36Sopenharmony_ci		ASSERT_NE(ENOSYS, errno) {
243062306a36Sopenharmony_ci			TH_LOG("Kernel does not support seccomp syscall!");
243162306a36Sopenharmony_ci		}
243262306a36Sopenharmony_ci		EXPECT_EQ(-1, ret);
243362306a36Sopenharmony_ci		EXPECT_EQ(EFAULT, errno) {
243462306a36Sopenharmony_ci			TH_LOG("Failed to detect that a known-good filter flag (0x%X) is supported!",
243562306a36Sopenharmony_ci			       flag);
243662306a36Sopenharmony_ci		}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci		all_flags |= flag;
243962306a36Sopenharmony_ci	}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	/*
244262306a36Sopenharmony_ci	 * Test detection of all known-good filter flags combined. But
244362306a36Sopenharmony_ci	 * for the exclusive flags we need to mask them out and try them
244462306a36Sopenharmony_ci	 * individually for the "all flags" testing.
244562306a36Sopenharmony_ci	 */
244662306a36Sopenharmony_ci	exclusive_mask = 0;
244762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(exclusive); i++)
244862306a36Sopenharmony_ci		exclusive_mask |= exclusive[i];
244962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(exclusive); i++) {
245062306a36Sopenharmony_ci		flag = all_flags & ~exclusive_mask;
245162306a36Sopenharmony_ci		flag |= exclusive[i];
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci		ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
245462306a36Sopenharmony_ci		EXPECT_EQ(-1, ret);
245562306a36Sopenharmony_ci		EXPECT_EQ(EFAULT, errno) {
245662306a36Sopenharmony_ci			TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!",
245762306a36Sopenharmony_ci			       flag);
245862306a36Sopenharmony_ci		}
245962306a36Sopenharmony_ci	}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	/* Test detection of an unknown filter flags, without exclusives. */
246262306a36Sopenharmony_ci	flag = -1;
246362306a36Sopenharmony_ci	flag &= ~exclusive_mask;
246462306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
246562306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
246662306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
246762306a36Sopenharmony_ci		TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported!",
246862306a36Sopenharmony_ci		       flag);
246962306a36Sopenharmony_ci	}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	/*
247262306a36Sopenharmony_ci	 * Test detection of an unknown filter flag that may simply need to be
247362306a36Sopenharmony_ci	 * added to this test
247462306a36Sopenharmony_ci	 */
247562306a36Sopenharmony_ci	flag = flags[ARRAY_SIZE(flags) - 1] << 1;
247662306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
247762306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
247862306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
247962306a36Sopenharmony_ci		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?",
248062306a36Sopenharmony_ci		       flag);
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci}
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ciTEST(TSYNC_first)
248562306a36Sopenharmony_ci{
248662306a36Sopenharmony_ci	struct sock_filter filter[] = {
248762306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
248862306a36Sopenharmony_ci	};
248962306a36Sopenharmony_ci	struct sock_fprog prog = {
249062306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
249162306a36Sopenharmony_ci		.filter = filter,
249262306a36Sopenharmony_ci	};
249362306a36Sopenharmony_ci	long ret;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0);
249662306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
249762306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
249862306a36Sopenharmony_ci	}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
250162306a36Sopenharmony_ci		      &prog);
250262306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
250362306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
250462306a36Sopenharmony_ci	}
250562306a36Sopenharmony_ci	EXPECT_EQ(0, ret) {
250662306a36Sopenharmony_ci		TH_LOG("Could not install initial filter with TSYNC!");
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci#define TSYNC_SIBLINGS 2
251162306a36Sopenharmony_cistruct tsync_sibling {
251262306a36Sopenharmony_ci	pthread_t tid;
251362306a36Sopenharmony_ci	pid_t system_tid;
251462306a36Sopenharmony_ci	sem_t *started;
251562306a36Sopenharmony_ci	pthread_cond_t *cond;
251662306a36Sopenharmony_ci	pthread_mutex_t *mutex;
251762306a36Sopenharmony_ci	int diverge;
251862306a36Sopenharmony_ci	int num_waits;
251962306a36Sopenharmony_ci	struct sock_fprog *prog;
252062306a36Sopenharmony_ci	struct __test_metadata *metadata;
252162306a36Sopenharmony_ci};
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci/*
252462306a36Sopenharmony_ci * To avoid joining joined threads (which is not allowed by Bionic),
252562306a36Sopenharmony_ci * make sure we both successfully join and clear the tid to skip a
252662306a36Sopenharmony_ci * later join attempt during fixture teardown. Any remaining threads
252762306a36Sopenharmony_ci * will be directly killed during teardown.
252862306a36Sopenharmony_ci */
252962306a36Sopenharmony_ci#define PTHREAD_JOIN(tid, status)					\
253062306a36Sopenharmony_ci	do {								\
253162306a36Sopenharmony_ci		int _rc = pthread_join(tid, status);			\
253262306a36Sopenharmony_ci		if (_rc) {						\
253362306a36Sopenharmony_ci			TH_LOG("pthread_join of tid %u failed: %d\n",	\
253462306a36Sopenharmony_ci				(unsigned int)tid, _rc);		\
253562306a36Sopenharmony_ci		} else {						\
253662306a36Sopenharmony_ci			tid = 0;					\
253762306a36Sopenharmony_ci		}							\
253862306a36Sopenharmony_ci	} while (0)
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ciFIXTURE(TSYNC) {
254162306a36Sopenharmony_ci	struct sock_fprog root_prog, apply_prog;
254262306a36Sopenharmony_ci	struct tsync_sibling sibling[TSYNC_SIBLINGS];
254362306a36Sopenharmony_ci	sem_t started;
254462306a36Sopenharmony_ci	pthread_cond_t cond;
254562306a36Sopenharmony_ci	pthread_mutex_t mutex;
254662306a36Sopenharmony_ci	int sibling_count;
254762306a36Sopenharmony_ci};
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ciFIXTURE_SETUP(TSYNC)
255062306a36Sopenharmony_ci{
255162306a36Sopenharmony_ci	struct sock_filter root_filter[] = {
255262306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
255362306a36Sopenharmony_ci	};
255462306a36Sopenharmony_ci	struct sock_filter apply_filter[] = {
255562306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
255662306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
255762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),
255862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
255962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
256062306a36Sopenharmony_ci	};
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	memset(&self->root_prog, 0, sizeof(self->root_prog));
256362306a36Sopenharmony_ci	memset(&self->apply_prog, 0, sizeof(self->apply_prog));
256462306a36Sopenharmony_ci	memset(&self->sibling, 0, sizeof(self->sibling));
256562306a36Sopenharmony_ci	self->root_prog.filter = malloc(sizeof(root_filter));
256662306a36Sopenharmony_ci	ASSERT_NE(NULL, self->root_prog.filter);
256762306a36Sopenharmony_ci	memcpy(self->root_prog.filter, &root_filter, sizeof(root_filter));
256862306a36Sopenharmony_ci	self->root_prog.len = (unsigned short)ARRAY_SIZE(root_filter);
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	self->apply_prog.filter = malloc(sizeof(apply_filter));
257162306a36Sopenharmony_ci	ASSERT_NE(NULL, self->apply_prog.filter);
257262306a36Sopenharmony_ci	memcpy(self->apply_prog.filter, &apply_filter, sizeof(apply_filter));
257362306a36Sopenharmony_ci	self->apply_prog.len = (unsigned short)ARRAY_SIZE(apply_filter);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	self->sibling_count = 0;
257662306a36Sopenharmony_ci	pthread_mutex_init(&self->mutex, NULL);
257762306a36Sopenharmony_ci	pthread_cond_init(&self->cond, NULL);
257862306a36Sopenharmony_ci	sem_init(&self->started, 0, 0);
257962306a36Sopenharmony_ci	self->sibling[0].tid = 0;
258062306a36Sopenharmony_ci	self->sibling[0].cond = &self->cond;
258162306a36Sopenharmony_ci	self->sibling[0].started = &self->started;
258262306a36Sopenharmony_ci	self->sibling[0].mutex = &self->mutex;
258362306a36Sopenharmony_ci	self->sibling[0].diverge = 0;
258462306a36Sopenharmony_ci	self->sibling[0].num_waits = 1;
258562306a36Sopenharmony_ci	self->sibling[0].prog = &self->root_prog;
258662306a36Sopenharmony_ci	self->sibling[0].metadata = _metadata;
258762306a36Sopenharmony_ci	self->sibling[1].tid = 0;
258862306a36Sopenharmony_ci	self->sibling[1].cond = &self->cond;
258962306a36Sopenharmony_ci	self->sibling[1].started = &self->started;
259062306a36Sopenharmony_ci	self->sibling[1].mutex = &self->mutex;
259162306a36Sopenharmony_ci	self->sibling[1].diverge = 0;
259262306a36Sopenharmony_ci	self->sibling[1].prog = &self->root_prog;
259362306a36Sopenharmony_ci	self->sibling[1].num_waits = 1;
259462306a36Sopenharmony_ci	self->sibling[1].metadata = _metadata;
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ciFIXTURE_TEARDOWN(TSYNC)
259862306a36Sopenharmony_ci{
259962306a36Sopenharmony_ci	int sib = 0;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	if (self->root_prog.filter)
260262306a36Sopenharmony_ci		free(self->root_prog.filter);
260362306a36Sopenharmony_ci	if (self->apply_prog.filter)
260462306a36Sopenharmony_ci		free(self->apply_prog.filter);
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	for ( ; sib < self->sibling_count; ++sib) {
260762306a36Sopenharmony_ci		struct tsync_sibling *s = &self->sibling[sib];
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci		if (!s->tid)
261062306a36Sopenharmony_ci			continue;
261162306a36Sopenharmony_ci		/*
261262306a36Sopenharmony_ci		 * If a thread is still running, it may be stuck, so hit
261362306a36Sopenharmony_ci		 * it over the head really hard.
261462306a36Sopenharmony_ci		 */
261562306a36Sopenharmony_ci		pthread_kill(s->tid, 9);
261662306a36Sopenharmony_ci	}
261762306a36Sopenharmony_ci	pthread_mutex_destroy(&self->mutex);
261862306a36Sopenharmony_ci	pthread_cond_destroy(&self->cond);
261962306a36Sopenharmony_ci	sem_destroy(&self->started);
262062306a36Sopenharmony_ci}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_civoid *tsync_sibling(void *data)
262362306a36Sopenharmony_ci{
262462306a36Sopenharmony_ci	long ret = 0;
262562306a36Sopenharmony_ci	struct tsync_sibling *me = data;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	me->system_tid = syscall(__NR_gettid);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	pthread_mutex_lock(me->mutex);
263062306a36Sopenharmony_ci	if (me->diverge) {
263162306a36Sopenharmony_ci		/* Just re-apply the root prog to fork the tree */
263262306a36Sopenharmony_ci		ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,
263362306a36Sopenharmony_ci				me->prog, 0, 0);
263462306a36Sopenharmony_ci	}
263562306a36Sopenharmony_ci	sem_post(me->started);
263662306a36Sopenharmony_ci	/* Return outside of started so parent notices failures. */
263762306a36Sopenharmony_ci	if (ret) {
263862306a36Sopenharmony_ci		pthread_mutex_unlock(me->mutex);
263962306a36Sopenharmony_ci		return (void *)SIBLING_EXIT_FAILURE;
264062306a36Sopenharmony_ci	}
264162306a36Sopenharmony_ci	do {
264262306a36Sopenharmony_ci		pthread_cond_wait(me->cond, me->mutex);
264362306a36Sopenharmony_ci		me->num_waits = me->num_waits - 1;
264462306a36Sopenharmony_ci	} while (me->num_waits);
264562306a36Sopenharmony_ci	pthread_mutex_unlock(me->mutex);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	ret = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
264862306a36Sopenharmony_ci	if (!ret)
264962306a36Sopenharmony_ci		return (void *)SIBLING_EXIT_NEWPRIVS;
265062306a36Sopenharmony_ci	read(-1, NULL, 0);
265162306a36Sopenharmony_ci	return (void *)SIBLING_EXIT_UNKILLED;
265262306a36Sopenharmony_ci}
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_civoid tsync_start_sibling(struct tsync_sibling *sibling)
265562306a36Sopenharmony_ci{
265662306a36Sopenharmony_ci	pthread_create(&sibling->tid, NULL, tsync_sibling, (void *)sibling);
265762306a36Sopenharmony_ci}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ciTEST_F(TSYNC, siblings_fail_prctl)
266062306a36Sopenharmony_ci{
266162306a36Sopenharmony_ci	long ret;
266262306a36Sopenharmony_ci	void *status;
266362306a36Sopenharmony_ci	struct sock_filter filter[] = {
266462306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
266562306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
266662306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1),
266762306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | EINVAL),
266862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
266962306a36Sopenharmony_ci	};
267062306a36Sopenharmony_ci	struct sock_fprog prog = {
267162306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
267262306a36Sopenharmony_ci		.filter = filter,
267362306a36Sopenharmony_ci	};
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
267662306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
267762306a36Sopenharmony_ci	}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	/* Check prctl failure detection by requesting sib 0 diverge. */
268062306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
268162306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
268262306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
268362306a36Sopenharmony_ci	}
268462306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
268562306a36Sopenharmony_ci		TH_LOG("setting filter failed");
268662306a36Sopenharmony_ci	}
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	self->sibling[0].diverge = 1;
268962306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
269062306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
269362306a36Sopenharmony_ci		sem_wait(&self->started);
269462306a36Sopenharmony_ci		self->sibling_count++;
269562306a36Sopenharmony_ci	}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	/* Signal the threads to clean up*/
269862306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
269962306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
270062306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	/* Ensure diverging sibling failed to call prctl. */
270562306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[0].tid, &status);
270662306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_FAILURE, (long)status);
270762306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[1].tid, &status);
270862306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
270962306a36Sopenharmony_ci}
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ciTEST_F(TSYNC, two_siblings_with_ancestor)
271262306a36Sopenharmony_ci{
271362306a36Sopenharmony_ci	long ret;
271462306a36Sopenharmony_ci	void *status;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
271762306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
271862306a36Sopenharmony_ci	}
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
272162306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
272262306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
272362306a36Sopenharmony_ci	}
272462306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
272562306a36Sopenharmony_ci		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
272662306a36Sopenharmony_ci	}
272762306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
272862306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
273162306a36Sopenharmony_ci		sem_wait(&self->started);
273262306a36Sopenharmony_ci		self->sibling_count++;
273362306a36Sopenharmony_ci	}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
273662306a36Sopenharmony_ci		      &self->apply_prog);
273762306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
273862306a36Sopenharmony_ci		TH_LOG("Could install filter on all threads!");
273962306a36Sopenharmony_ci	}
274062306a36Sopenharmony_ci	/* Tell the siblings to test the policy */
274162306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
274262306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
274362306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
274462306a36Sopenharmony_ci	}
274562306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
274662306a36Sopenharmony_ci	/* Ensure they are both killed and don't exit cleanly. */
274762306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[0].tid, &status);
274862306a36Sopenharmony_ci	EXPECT_EQ(0x0, (long)status);
274962306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[1].tid, &status);
275062306a36Sopenharmony_ci	EXPECT_EQ(0x0, (long)status);
275162306a36Sopenharmony_ci}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ciTEST_F(TSYNC, two_sibling_want_nnp)
275462306a36Sopenharmony_ci{
275562306a36Sopenharmony_ci	void *status;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	/* start siblings before any prctl() operations */
275862306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
275962306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
276062306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
276162306a36Sopenharmony_ci		sem_wait(&self->started);
276262306a36Sopenharmony_ci		self->sibling_count++;
276362306a36Sopenharmony_ci	}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	/* Tell the siblings to test no policy */
276662306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
276762306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
276862306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
276962306a36Sopenharmony_ci	}
277062306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	/* Ensure they are both upset about lacking nnp. */
277362306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[0].tid, &status);
277462306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status);
277562306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[1].tid, &status);
277662306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status);
277762306a36Sopenharmony_ci}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ciTEST_F(TSYNC, two_siblings_with_no_filter)
278062306a36Sopenharmony_ci{
278162306a36Sopenharmony_ci	long ret;
278262306a36Sopenharmony_ci	void *status;
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	/* start siblings before any prctl() operations */
278562306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
278662306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
278762306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
278862306a36Sopenharmony_ci		sem_wait(&self->started);
278962306a36Sopenharmony_ci		self->sibling_count++;
279062306a36Sopenharmony_ci	}
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
279362306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
279462306a36Sopenharmony_ci	}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
279762306a36Sopenharmony_ci		      &self->apply_prog);
279862306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
279962306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
280262306a36Sopenharmony_ci		TH_LOG("Could install filter on all threads!");
280362306a36Sopenharmony_ci	}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	/* Tell the siblings to test the policy */
280662306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
280762306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
280862306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
280962306a36Sopenharmony_ci	}
281062306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	/* Ensure they are both killed and don't exit cleanly. */
281362306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[0].tid, &status);
281462306a36Sopenharmony_ci	EXPECT_EQ(0x0, (long)status);
281562306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[1].tid, &status);
281662306a36Sopenharmony_ci	EXPECT_EQ(0x0, (long)status);
281762306a36Sopenharmony_ci}
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ciTEST_F(TSYNC, two_siblings_with_one_divergence)
282062306a36Sopenharmony_ci{
282162306a36Sopenharmony_ci	long ret;
282262306a36Sopenharmony_ci	void *status;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
282562306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
282962306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
283062306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
283162306a36Sopenharmony_ci	}
283262306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
283362306a36Sopenharmony_ci		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
283462306a36Sopenharmony_ci	}
283562306a36Sopenharmony_ci	self->sibling[0].diverge = 1;
283662306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
283762306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
284062306a36Sopenharmony_ci		sem_wait(&self->started);
284162306a36Sopenharmony_ci		self->sibling_count++;
284262306a36Sopenharmony_ci	}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
284562306a36Sopenharmony_ci		      &self->apply_prog);
284662306a36Sopenharmony_ci	ASSERT_EQ(self->sibling[0].system_tid, ret) {
284762306a36Sopenharmony_ci		TH_LOG("Did not fail on diverged sibling.");
284862306a36Sopenharmony_ci	}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	/* Wake the threads */
285162306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
285262306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
285362306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
285462306a36Sopenharmony_ci	}
285562306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	/* Ensure they are both unkilled. */
285862306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[0].tid, &status);
285962306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
286062306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[1].tid, &status);
286162306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
286262306a36Sopenharmony_ci}
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ciTEST_F(TSYNC, two_siblings_with_one_divergence_no_tid_in_err)
286562306a36Sopenharmony_ci{
286662306a36Sopenharmony_ci	long ret, flags;
286762306a36Sopenharmony_ci	void *status;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
287062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
287162306a36Sopenharmony_ci	}
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
287462306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
287562306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
287662306a36Sopenharmony_ci	}
287762306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
287862306a36Sopenharmony_ci		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
287962306a36Sopenharmony_ci	}
288062306a36Sopenharmony_ci	self->sibling[0].diverge = 1;
288162306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
288262306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
288562306a36Sopenharmony_ci		sem_wait(&self->started);
288662306a36Sopenharmony_ci		self->sibling_count++;
288762306a36Sopenharmony_ci	}
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	flags = SECCOMP_FILTER_FLAG_TSYNC | \
289062306a36Sopenharmony_ci		SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
289162306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, flags, &self->apply_prog);
289262306a36Sopenharmony_ci	ASSERT_EQ(ESRCH, errno) {
289362306a36Sopenharmony_ci		TH_LOG("Did not return ESRCH for diverged sibling.");
289462306a36Sopenharmony_ci	}
289562306a36Sopenharmony_ci	ASSERT_EQ(-1, ret) {
289662306a36Sopenharmony_ci		TH_LOG("Did not fail on diverged sibling.");
289762306a36Sopenharmony_ci	}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	/* Wake the threads */
290062306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
290162306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
290262306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
290362306a36Sopenharmony_ci	}
290462306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	/* Ensure they are both unkilled. */
290762306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[0].tid, &status);
290862306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
290962306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[1].tid, &status);
291062306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
291162306a36Sopenharmony_ci}
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ciTEST_F(TSYNC, two_siblings_not_under_filter)
291462306a36Sopenharmony_ci{
291562306a36Sopenharmony_ci	long ret, sib;
291662306a36Sopenharmony_ci	void *status;
291762306a36Sopenharmony_ci	struct timespec delay = { .tv_nsec = 100000000 };
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
292062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
292162306a36Sopenharmony_ci	}
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	/*
292462306a36Sopenharmony_ci	 * Sibling 0 will have its own seccomp policy
292562306a36Sopenharmony_ci	 * and Sibling 1 will not be under seccomp at
292662306a36Sopenharmony_ci	 * all. Sibling 1 will enter seccomp and 0
292762306a36Sopenharmony_ci	 * will cause failure.
292862306a36Sopenharmony_ci	 */
292962306a36Sopenharmony_ci	self->sibling[0].diverge = 1;
293062306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[0]);
293162306a36Sopenharmony_ci	tsync_start_sibling(&self->sibling[1]);
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	while (self->sibling_count < TSYNC_SIBLINGS) {
293462306a36Sopenharmony_ci		sem_wait(&self->started);
293562306a36Sopenharmony_ci		self->sibling_count++;
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
293962306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
294062306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
294162306a36Sopenharmony_ci	}
294262306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
294362306a36Sopenharmony_ci		TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
294462306a36Sopenharmony_ci	}
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
294762306a36Sopenharmony_ci		      &self->apply_prog);
294862306a36Sopenharmony_ci	ASSERT_EQ(ret, self->sibling[0].system_tid) {
294962306a36Sopenharmony_ci		TH_LOG("Did not fail on diverged sibling.");
295062306a36Sopenharmony_ci	}
295162306a36Sopenharmony_ci	sib = 1;
295262306a36Sopenharmony_ci	if (ret == self->sibling[0].system_tid)
295362306a36Sopenharmony_ci		sib = 0;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	/* Increment the other siblings num_waits so we can clean up
295862306a36Sopenharmony_ci	 * the one we just saw.
295962306a36Sopenharmony_ci	 */
296062306a36Sopenharmony_ci	self->sibling[!sib].num_waits += 1;
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	/* Signal the thread to clean up*/
296362306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
296462306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
296562306a36Sopenharmony_ci	}
296662306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
296762306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[sib].tid, &status);
296862306a36Sopenharmony_ci	EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
296962306a36Sopenharmony_ci	/* Poll for actual task death. pthread_join doesn't guarantee it. */
297062306a36Sopenharmony_ci	while (!kill(self->sibling[sib].system_tid, 0))
297162306a36Sopenharmony_ci		nanosleep(&delay, NULL);
297262306a36Sopenharmony_ci	/* Switch to the remaining sibling */
297362306a36Sopenharmony_ci	sib = !sib;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
297662306a36Sopenharmony_ci		      &self->apply_prog);
297762306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
297862306a36Sopenharmony_ci		TH_LOG("Expected the remaining sibling to sync");
297962306a36Sopenharmony_ci	};
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	pthread_mutex_lock(&self->mutex);
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	/* If remaining sibling didn't have a chance to wake up during
298462306a36Sopenharmony_ci	 * the first broadcast, manually reduce the num_waits now.
298562306a36Sopenharmony_ci	 */
298662306a36Sopenharmony_ci	if (self->sibling[sib].num_waits > 1)
298762306a36Sopenharmony_ci		self->sibling[sib].num_waits = 1;
298862306a36Sopenharmony_ci	ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
298962306a36Sopenharmony_ci		TH_LOG("cond broadcast non-zero");
299062306a36Sopenharmony_ci	}
299162306a36Sopenharmony_ci	pthread_mutex_unlock(&self->mutex);
299262306a36Sopenharmony_ci	PTHREAD_JOIN(self->sibling[sib].tid, &status);
299362306a36Sopenharmony_ci	EXPECT_EQ(0, (long)status);
299462306a36Sopenharmony_ci	/* Poll for actual task death. pthread_join doesn't guarantee it. */
299562306a36Sopenharmony_ci	while (!kill(self->sibling[sib].system_tid, 0))
299662306a36Sopenharmony_ci		nanosleep(&delay, NULL);
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
299962306a36Sopenharmony_ci		      &self->apply_prog);
300062306a36Sopenharmony_ci	ASSERT_EQ(0, ret);  /* just us chickens */
300162306a36Sopenharmony_ci}
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci/* Make sure restarted syscalls are seen directly as "restart_syscall". */
300462306a36Sopenharmony_ciTEST(syscall_restart)
300562306a36Sopenharmony_ci{
300662306a36Sopenharmony_ci	long ret;
300762306a36Sopenharmony_ci	unsigned long msg;
300862306a36Sopenharmony_ci	pid_t child_pid;
300962306a36Sopenharmony_ci	int pipefd[2];
301062306a36Sopenharmony_ci	int status;
301162306a36Sopenharmony_ci	siginfo_t info = { };
301262306a36Sopenharmony_ci	struct sock_filter filter[] = {
301362306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
301462306a36Sopenharmony_ci			 offsetof(struct seccomp_data, nr)),
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci#ifdef __NR_sigreturn
301762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_sigreturn, 7, 0),
301862306a36Sopenharmony_ci#endif
301962306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 6, 0),
302062306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit, 5, 0),
302162306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_rt_sigreturn, 4, 0),
302262306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_nanosleep, 5, 0),
302362306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_clock_nanosleep, 4, 0),
302462306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_restart_syscall, 4, 0),
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci		/* Allow __NR_write for easy logging. */
302762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_write, 0, 1),
302862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
302962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
303062306a36Sopenharmony_ci		/* The nanosleep jump target. */
303162306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100),
303262306a36Sopenharmony_ci		/* The restart_syscall jump target. */
303362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200),
303462306a36Sopenharmony_ci	};
303562306a36Sopenharmony_ci	struct sock_fprog prog = {
303662306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
303762306a36Sopenharmony_ci		.filter = filter,
303862306a36Sopenharmony_ci	};
303962306a36Sopenharmony_ci#if defined(__arm__)
304062306a36Sopenharmony_ci	struct utsname utsbuf;
304162306a36Sopenharmony_ci#endif
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	ASSERT_EQ(0, pipe(pipefd));
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	child_pid = fork();
304662306a36Sopenharmony_ci	ASSERT_LE(0, child_pid);
304762306a36Sopenharmony_ci	if (child_pid == 0) {
304862306a36Sopenharmony_ci		/* Child uses EXPECT not ASSERT to deliver status correctly. */
304962306a36Sopenharmony_ci		char buf = ' ';
305062306a36Sopenharmony_ci		struct timespec timeout = { };
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci		/* Attach parent as tracer and stop. */
305362306a36Sopenharmony_ci		EXPECT_EQ(0, ptrace(PTRACE_TRACEME));
305462306a36Sopenharmony_ci		EXPECT_EQ(0, raise(SIGSTOP));
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci		EXPECT_EQ(0, close(pipefd[1]));
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci		EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
305962306a36Sopenharmony_ci			TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
306062306a36Sopenharmony_ci		}
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci		ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
306362306a36Sopenharmony_ci		EXPECT_EQ(0, ret) {
306462306a36Sopenharmony_ci			TH_LOG("Failed to install filter!");
306562306a36Sopenharmony_ci		}
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci		EXPECT_EQ(1, read(pipefd[0], &buf, 1)) {
306862306a36Sopenharmony_ci			TH_LOG("Failed to read() sync from parent");
306962306a36Sopenharmony_ci		}
307062306a36Sopenharmony_ci		EXPECT_EQ('.', buf) {
307162306a36Sopenharmony_ci			TH_LOG("Failed to get sync data from read()");
307262306a36Sopenharmony_ci		}
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci		/* Start nanosleep to be interrupted. */
307562306a36Sopenharmony_ci		timeout.tv_sec = 1;
307662306a36Sopenharmony_ci		errno = 0;
307762306a36Sopenharmony_ci		EXPECT_EQ(0, nanosleep(&timeout, NULL)) {
307862306a36Sopenharmony_ci			TH_LOG("Call to nanosleep() failed (errno %d: %s)",
307962306a36Sopenharmony_ci				errno, strerror(errno));
308062306a36Sopenharmony_ci		}
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci		/* Read final sync from parent. */
308362306a36Sopenharmony_ci		EXPECT_EQ(1, read(pipefd[0], &buf, 1)) {
308462306a36Sopenharmony_ci			TH_LOG("Failed final read() from parent");
308562306a36Sopenharmony_ci		}
308662306a36Sopenharmony_ci		EXPECT_EQ('!', buf) {
308762306a36Sopenharmony_ci			TH_LOG("Failed to get final data from read()");
308862306a36Sopenharmony_ci		}
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci		/* Directly report the status of our test harness results. */
309162306a36Sopenharmony_ci		syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS
309262306a36Sopenharmony_ci						     : EXIT_FAILURE);
309362306a36Sopenharmony_ci	}
309462306a36Sopenharmony_ci	EXPECT_EQ(0, close(pipefd[0]));
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	/* Attach to child, setup options, and release. */
309762306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
309862306a36Sopenharmony_ci	ASSERT_EQ(true, WIFSTOPPED(status));
309962306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_SETOPTIONS, child_pid, NULL,
310062306a36Sopenharmony_ci			    PTRACE_O_TRACESECCOMP));
310162306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
310262306a36Sopenharmony_ci	ASSERT_EQ(1, write(pipefd[1], ".", 1));
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	/* Wait for nanosleep() to start. */
310562306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
310662306a36Sopenharmony_ci	ASSERT_EQ(true, WIFSTOPPED(status));
310762306a36Sopenharmony_ci	ASSERT_EQ(SIGTRAP, WSTOPSIG(status));
310862306a36Sopenharmony_ci	ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16));
310962306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg));
311062306a36Sopenharmony_ci	ASSERT_EQ(0x100, msg);
311162306a36Sopenharmony_ci	ret = get_syscall(_metadata, child_pid);
311262306a36Sopenharmony_ci	EXPECT_TRUE(ret == __NR_nanosleep || ret == __NR_clock_nanosleep);
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	/* Might as well check siginfo for sanity while we're here. */
311562306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
311662306a36Sopenharmony_ci	ASSERT_EQ(SIGTRAP, info.si_signo);
311762306a36Sopenharmony_ci	ASSERT_EQ(SIGTRAP | (PTRACE_EVENT_SECCOMP << 8), info.si_code);
311862306a36Sopenharmony_ci	EXPECT_EQ(0, info.si_errno);
311962306a36Sopenharmony_ci	EXPECT_EQ(getuid(), info.si_uid);
312062306a36Sopenharmony_ci	/* Verify signal delivery came from child (seccomp-triggered). */
312162306a36Sopenharmony_ci	EXPECT_EQ(child_pid, info.si_pid);
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	/* Interrupt nanosleep with SIGSTOP (which we'll need to handle). */
312462306a36Sopenharmony_ci	ASSERT_EQ(0, kill(child_pid, SIGSTOP));
312562306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
312662306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
312762306a36Sopenharmony_ci	ASSERT_EQ(true, WIFSTOPPED(status));
312862306a36Sopenharmony_ci	ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
312962306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
313062306a36Sopenharmony_ci	/*
313162306a36Sopenharmony_ci	 * There is no siginfo on SIGSTOP any more, so we can't verify
313262306a36Sopenharmony_ci	 * signal delivery came from parent now (getpid() == info.si_pid).
313362306a36Sopenharmony_ci	 * https://lkml.kernel.org/r/CAGXu5jJaZAOzP1qFz66tYrtbuywqb+UN2SOA1VLHpCCOiYvYeg@mail.gmail.com
313462306a36Sopenharmony_ci	 * At least verify the SIGSTOP via PTRACE_GETSIGINFO.
313562306a36Sopenharmony_ci	 */
313662306a36Sopenharmony_ci	EXPECT_EQ(SIGSTOP, info.si_signo);
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	/* Restart nanosleep with SIGCONT, which triggers restart_syscall. */
313962306a36Sopenharmony_ci	ASSERT_EQ(0, kill(child_pid, SIGCONT));
314062306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
314162306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
314262306a36Sopenharmony_ci	ASSERT_EQ(true, WIFSTOPPED(status));
314362306a36Sopenharmony_ci	ASSERT_EQ(SIGCONT, WSTOPSIG(status));
314462306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	/* Wait for restart_syscall() to start. */
314762306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
314862306a36Sopenharmony_ci	ASSERT_EQ(true, WIFSTOPPED(status));
314962306a36Sopenharmony_ci	ASSERT_EQ(SIGTRAP, WSTOPSIG(status));
315062306a36Sopenharmony_ci	ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16));
315162306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg));
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	ASSERT_EQ(0x200, msg);
315462306a36Sopenharmony_ci	ret = get_syscall(_metadata, child_pid);
315562306a36Sopenharmony_ci#if defined(__arm__)
315662306a36Sopenharmony_ci	/*
315762306a36Sopenharmony_ci	 * FIXME:
315862306a36Sopenharmony_ci	 * - native ARM registers do NOT expose true syscall.
315962306a36Sopenharmony_ci	 * - compat ARM registers on ARM64 DO expose true syscall.
316062306a36Sopenharmony_ci	 */
316162306a36Sopenharmony_ci	ASSERT_EQ(0, uname(&utsbuf));
316262306a36Sopenharmony_ci	if (strncmp(utsbuf.machine, "arm", 3) == 0) {
316362306a36Sopenharmony_ci		EXPECT_EQ(__NR_nanosleep, ret);
316462306a36Sopenharmony_ci	} else
316562306a36Sopenharmony_ci#endif
316662306a36Sopenharmony_ci	{
316762306a36Sopenharmony_ci		EXPECT_EQ(__NR_restart_syscall, ret);
316862306a36Sopenharmony_ci	}
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci	/* Write again to end test. */
317162306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
317262306a36Sopenharmony_ci	ASSERT_EQ(1, write(pipefd[1], "!", 1));
317362306a36Sopenharmony_ci	EXPECT_EQ(0, close(pipefd[1]));
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
317662306a36Sopenharmony_ci	if (WIFSIGNALED(status) || WEXITSTATUS(status))
317762306a36Sopenharmony_ci		_metadata->passed = 0;
317862306a36Sopenharmony_ci}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ciTEST_SIGNAL(filter_flag_log, SIGSYS)
318162306a36Sopenharmony_ci{
318262306a36Sopenharmony_ci	struct sock_filter allow_filter[] = {
318362306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
318462306a36Sopenharmony_ci	};
318562306a36Sopenharmony_ci	struct sock_filter kill_filter[] = {
318662306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
318762306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
318862306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1),
318962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
319062306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
319162306a36Sopenharmony_ci	};
319262306a36Sopenharmony_ci	struct sock_fprog allow_prog = {
319362306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(allow_filter),
319462306a36Sopenharmony_ci		.filter = allow_filter,
319562306a36Sopenharmony_ci	};
319662306a36Sopenharmony_ci	struct sock_fprog kill_prog = {
319762306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(kill_filter),
319862306a36Sopenharmony_ci		.filter = kill_filter,
319962306a36Sopenharmony_ci	};
320062306a36Sopenharmony_ci	long ret;
320162306a36Sopenharmony_ci	pid_t parent = getppid();
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
320462306a36Sopenharmony_ci	ASSERT_EQ(0, ret);
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	/* Verify that the FILTER_FLAG_LOG flag isn't accepted in strict mode */
320762306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_STRICT, SECCOMP_FILTER_FLAG_LOG,
320862306a36Sopenharmony_ci		      &allow_prog);
320962306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
321062306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
321162306a36Sopenharmony_ci	}
321262306a36Sopenharmony_ci	EXPECT_NE(0, ret) {
321362306a36Sopenharmony_ci		TH_LOG("Kernel accepted FILTER_FLAG_LOG flag in strict mode!");
321462306a36Sopenharmony_ci	}
321562306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno) {
321662306a36Sopenharmony_ci		TH_LOG("Kernel returned unexpected errno for FILTER_FLAG_LOG flag in strict mode!");
321762306a36Sopenharmony_ci	}
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	/* Verify that a simple, permissive filter can be added with no flags */
322062306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &allow_prog);
322162306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	/* See if the same filter can be added with the FILTER_FLAG_LOG flag */
322462306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG,
322562306a36Sopenharmony_ci		      &allow_prog);
322662306a36Sopenharmony_ci	ASSERT_NE(EINVAL, errno) {
322762306a36Sopenharmony_ci		TH_LOG("Kernel does not support the FILTER_FLAG_LOG flag!");
322862306a36Sopenharmony_ci	}
322962306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	/* Ensure that the kill filter works with the FILTER_FLAG_LOG flag */
323262306a36Sopenharmony_ci	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG,
323362306a36Sopenharmony_ci		      &kill_prog);
323462306a36Sopenharmony_ci	EXPECT_EQ(0, ret);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	EXPECT_EQ(parent, syscall(__NR_getppid));
323762306a36Sopenharmony_ci	/* getpid() should never return. */
323862306a36Sopenharmony_ci	EXPECT_EQ(0, syscall(__NR_getpid));
323962306a36Sopenharmony_ci}
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ciTEST(get_action_avail)
324262306a36Sopenharmony_ci{
324362306a36Sopenharmony_ci	__u32 actions[] = { SECCOMP_RET_KILL_THREAD, SECCOMP_RET_TRAP,
324462306a36Sopenharmony_ci			    SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE,
324562306a36Sopenharmony_ci			    SECCOMP_RET_LOG,   SECCOMP_RET_ALLOW };
324662306a36Sopenharmony_ci	__u32 unknown_action = 0x10000000U;
324762306a36Sopenharmony_ci	int i;
324862306a36Sopenharmony_ci	long ret;
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_ci	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[0]);
325162306a36Sopenharmony_ci	ASSERT_NE(ENOSYS, errno) {
325262306a36Sopenharmony_ci		TH_LOG("Kernel does not support seccomp syscall!");
325362306a36Sopenharmony_ci	}
325462306a36Sopenharmony_ci	ASSERT_NE(EINVAL, errno) {
325562306a36Sopenharmony_ci		TH_LOG("Kernel does not support SECCOMP_GET_ACTION_AVAIL operation!");
325662306a36Sopenharmony_ci	}
325762306a36Sopenharmony_ci	EXPECT_EQ(ret, 0);
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(actions); i++) {
326062306a36Sopenharmony_ci		ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[i]);
326162306a36Sopenharmony_ci		EXPECT_EQ(ret, 0) {
326262306a36Sopenharmony_ci			TH_LOG("Expected action (0x%X) not available!",
326362306a36Sopenharmony_ci			       actions[i]);
326462306a36Sopenharmony_ci		}
326562306a36Sopenharmony_ci	}
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	/* Check that an unknown action is handled properly (EOPNOTSUPP) */
326862306a36Sopenharmony_ci	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &unknown_action);
326962306a36Sopenharmony_ci	EXPECT_EQ(ret, -1);
327062306a36Sopenharmony_ci	EXPECT_EQ(errno, EOPNOTSUPP);
327162306a36Sopenharmony_ci}
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ciTEST(get_metadata)
327462306a36Sopenharmony_ci{
327562306a36Sopenharmony_ci	pid_t pid;
327662306a36Sopenharmony_ci	int pipefd[2];
327762306a36Sopenharmony_ci	char buf;
327862306a36Sopenharmony_ci	struct seccomp_metadata md;
327962306a36Sopenharmony_ci	long ret;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	/* Only real root can get metadata. */
328262306a36Sopenharmony_ci	if (geteuid()) {
328362306a36Sopenharmony_ci		SKIP(return, "get_metadata requires real root");
328462306a36Sopenharmony_ci		return;
328562306a36Sopenharmony_ci	}
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	ASSERT_EQ(0, pipe(pipefd));
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_ci	pid = fork();
329062306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
329162306a36Sopenharmony_ci	if (pid == 0) {
329262306a36Sopenharmony_ci		struct sock_filter filter[] = {
329362306a36Sopenharmony_ci			BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
329462306a36Sopenharmony_ci		};
329562306a36Sopenharmony_ci		struct sock_fprog prog = {
329662306a36Sopenharmony_ci			.len = (unsigned short)ARRAY_SIZE(filter),
329762306a36Sopenharmony_ci			.filter = filter,
329862306a36Sopenharmony_ci		};
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci		/* one with log, one without */
330162306a36Sopenharmony_ci		EXPECT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER,
330262306a36Sopenharmony_ci				     SECCOMP_FILTER_FLAG_LOG, &prog));
330362306a36Sopenharmony_ci		EXPECT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog));
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci		EXPECT_EQ(0, close(pipefd[0]));
330662306a36Sopenharmony_ci		ASSERT_EQ(1, write(pipefd[1], "1", 1));
330762306a36Sopenharmony_ci		ASSERT_EQ(0, close(pipefd[1]));
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci		while (1)
331062306a36Sopenharmony_ci			sleep(100);
331162306a36Sopenharmony_ci	}
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	ASSERT_EQ(0, close(pipefd[1]));
331462306a36Sopenharmony_ci	ASSERT_EQ(1, read(pipefd[0], &buf, 1));
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid));
331762306a36Sopenharmony_ci	ASSERT_EQ(pid, waitpid(pid, NULL, 0));
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	/* Past here must not use ASSERT or child process is never killed. */
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	md.filter_off = 0;
332262306a36Sopenharmony_ci	errno = 0;
332362306a36Sopenharmony_ci	ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md);
332462306a36Sopenharmony_ci	EXPECT_EQ(sizeof(md), ret) {
332562306a36Sopenharmony_ci		if (errno == EINVAL)
332662306a36Sopenharmony_ci			SKIP(goto skip, "Kernel does not support PTRACE_SECCOMP_GET_METADATA (missing CONFIG_CHECKPOINT_RESTORE?)");
332762306a36Sopenharmony_ci	}
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci	EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG);
333062306a36Sopenharmony_ci	EXPECT_EQ(md.filter_off, 0);
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	md.filter_off = 1;
333362306a36Sopenharmony_ci	ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md);
333462306a36Sopenharmony_ci	EXPECT_EQ(sizeof(md), ret);
333562306a36Sopenharmony_ci	EXPECT_EQ(md.flags, 0);
333662306a36Sopenharmony_ci	EXPECT_EQ(md.filter_off, 1);
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ciskip:
333962306a36Sopenharmony_ci	ASSERT_EQ(0, kill(pid, SIGKILL));
334062306a36Sopenharmony_ci}
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_cistatic int user_notif_syscall(int nr, unsigned int flags)
334362306a36Sopenharmony_ci{
334462306a36Sopenharmony_ci	struct sock_filter filter[] = {
334562306a36Sopenharmony_ci		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
334662306a36Sopenharmony_ci			offsetof(struct seccomp_data, nr)),
334762306a36Sopenharmony_ci		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, nr, 0, 1),
334862306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_USER_NOTIF),
334962306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
335062306a36Sopenharmony_ci	};
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	struct sock_fprog prog = {
335362306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
335462306a36Sopenharmony_ci		.filter = filter,
335562306a36Sopenharmony_ci	};
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci	return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog);
335862306a36Sopenharmony_ci}
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci#define USER_NOTIF_MAGIC INT_MAX
336162306a36Sopenharmony_ciTEST(user_notification_basic)
336262306a36Sopenharmony_ci{
336362306a36Sopenharmony_ci	pid_t pid;
336462306a36Sopenharmony_ci	long ret;
336562306a36Sopenharmony_ci	int status, listener;
336662306a36Sopenharmony_ci	struct seccomp_notif req = {};
336762306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
336862306a36Sopenharmony_ci	struct pollfd pollfd;
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	struct sock_filter filter[] = {
337162306a36Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
337262306a36Sopenharmony_ci	};
337362306a36Sopenharmony_ci	struct sock_fprog prog = {
337462306a36Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
337562306a36Sopenharmony_ci		.filter = filter,
337662306a36Sopenharmony_ci	};
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
337962306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
338062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
338162306a36Sopenharmony_ci	}
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	pid = fork();
338462306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	/* Check that we get -ENOSYS with no listener attached */
338762306a36Sopenharmony_ci	if (pid == 0) {
338862306a36Sopenharmony_ci		if (user_notif_syscall(__NR_getppid, 0) < 0)
338962306a36Sopenharmony_ci			exit(1);
339062306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
339162306a36Sopenharmony_ci		exit(ret >= 0 || errno != ENOSYS);
339262306a36Sopenharmony_ci	}
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
339562306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
339662306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	/* Add some no-op filters for grins. */
339962306a36Sopenharmony_ci	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
340062306a36Sopenharmony_ci	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
340162306a36Sopenharmony_ci	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
340262306a36Sopenharmony_ci	EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci	/* Check that the basic notification machinery works */
340562306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
340662306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
340762306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	/* Installing a second listener in the chain should EBUSY */
341062306a36Sopenharmony_ci	EXPECT_EQ(user_notif_syscall(__NR_getppid,
341162306a36Sopenharmony_ci				     SECCOMP_FILTER_FLAG_NEW_LISTENER),
341262306a36Sopenharmony_ci		  -1);
341362306a36Sopenharmony_ci	EXPECT_EQ(errno, EBUSY);
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	pid = fork();
341662306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	if (pid == 0) {
341962306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
342062306a36Sopenharmony_ci		exit(ret != USER_NOTIF_MAGIC);
342162306a36Sopenharmony_ci	}
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	pollfd.fd = listener;
342462306a36Sopenharmony_ci	pollfd.events = POLLIN | POLLOUT;
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	EXPECT_GT(poll(&pollfd, 1, -1), 0);
342762306a36Sopenharmony_ci	EXPECT_EQ(pollfd.revents, POLLIN);
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	/* Test that we can't pass garbage to the kernel. */
343062306a36Sopenharmony_ci	memset(&req, 0, sizeof(req));
343162306a36Sopenharmony_ci	req.pid = -1;
343262306a36Sopenharmony_ci	errno = 0;
343362306a36Sopenharmony_ci	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req);
343462306a36Sopenharmony_ci	EXPECT_EQ(-1, ret);
343562306a36Sopenharmony_ci	EXPECT_EQ(EINVAL, errno);
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	if (ret) {
343862306a36Sopenharmony_ci		req.pid = 0;
343962306a36Sopenharmony_ci		EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
344062306a36Sopenharmony_ci	}
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_ci	pollfd.fd = listener;
344362306a36Sopenharmony_ci	pollfd.events = POLLIN | POLLOUT;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	EXPECT_GT(poll(&pollfd, 1, -1), 0);
344662306a36Sopenharmony_ci	EXPECT_EQ(pollfd.revents, POLLOUT);
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	EXPECT_EQ(req.data.nr,  __NR_getppid);
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	resp.id = req.id;
345162306a36Sopenharmony_ci	resp.error = 0;
345262306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	/* check that we make sure flags == 0 */
345562306a36Sopenharmony_ci	resp.flags = 1;
345662306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
345762306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	resp.flags = 0;
346062306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
346362306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
346462306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
346562306a36Sopenharmony_ci}
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ciTEST(user_notification_with_tsync)
346862306a36Sopenharmony_ci{
346962306a36Sopenharmony_ci	int ret;
347062306a36Sopenharmony_ci	unsigned int flags;
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
347362306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
347462306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
347562306a36Sopenharmony_ci	}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	/* these were exclusive */
347862306a36Sopenharmony_ci	flags = SECCOMP_FILTER_FLAG_NEW_LISTENER |
347962306a36Sopenharmony_ci		SECCOMP_FILTER_FLAG_TSYNC;
348062306a36Sopenharmony_ci	ASSERT_EQ(-1, user_notif_syscall(__NR_getppid, flags));
348162306a36Sopenharmony_ci	ASSERT_EQ(EINVAL, errno);
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	/* but now they're not */
348462306a36Sopenharmony_ci	flags |= SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
348562306a36Sopenharmony_ci	ret = user_notif_syscall(__NR_getppid, flags);
348662306a36Sopenharmony_ci	close(ret);
348762306a36Sopenharmony_ci	ASSERT_LE(0, ret);
348862306a36Sopenharmony_ci}
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ciTEST(user_notification_kill_in_middle)
349162306a36Sopenharmony_ci{
349262306a36Sopenharmony_ci	pid_t pid;
349362306a36Sopenharmony_ci	long ret;
349462306a36Sopenharmony_ci	int listener;
349562306a36Sopenharmony_ci	struct seccomp_notif req = {};
349662306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
349962306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
350062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
350162306a36Sopenharmony_ci	}
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
350462306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
350562306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	/*
350862306a36Sopenharmony_ci	 * Check that nothing bad happens when we kill the task in the middle
350962306a36Sopenharmony_ci	 * of a syscall.
351062306a36Sopenharmony_ci	 */
351162306a36Sopenharmony_ci	pid = fork();
351262306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	if (pid == 0) {
351562306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
351662306a36Sopenharmony_ci		exit(ret != USER_NOTIF_MAGIC);
351762306a36Sopenharmony_ci	}
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
352062306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), 0);
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci	EXPECT_EQ(kill(pid, SIGKILL), 0);
352362306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, NULL, 0), pid);
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), -1);
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci	resp.id = req.id;
352862306a36Sopenharmony_ci	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
352962306a36Sopenharmony_ci	EXPECT_EQ(ret, -1);
353062306a36Sopenharmony_ci	EXPECT_EQ(errno, ENOENT);
353162306a36Sopenharmony_ci}
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_cistatic int handled = -1;
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_cistatic void signal_handler(int signal)
353662306a36Sopenharmony_ci{
353762306a36Sopenharmony_ci	if (write(handled, "c", 1) != 1)
353862306a36Sopenharmony_ci		perror("write from signal");
353962306a36Sopenharmony_ci}
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ciTEST(user_notification_signal)
354262306a36Sopenharmony_ci{
354362306a36Sopenharmony_ci	pid_t pid;
354462306a36Sopenharmony_ci	long ret;
354562306a36Sopenharmony_ci	int status, listener, sk_pair[2];
354662306a36Sopenharmony_ci	struct seccomp_notif req = {};
354762306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
354862306a36Sopenharmony_ci	char c;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
355162306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
355262306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
355362306a36Sopenharmony_ci	}
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_gettid,
355862306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
355962306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	pid = fork();
356262306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	if (pid == 0) {
356562306a36Sopenharmony_ci		close(sk_pair[0]);
356662306a36Sopenharmony_ci		handled = sk_pair[1];
356762306a36Sopenharmony_ci		if (signal(SIGUSR1, signal_handler) == SIG_ERR) {
356862306a36Sopenharmony_ci			perror("signal");
356962306a36Sopenharmony_ci			exit(1);
357062306a36Sopenharmony_ci		}
357162306a36Sopenharmony_ci		/*
357262306a36Sopenharmony_ci		 * ERESTARTSYS behavior is a bit hard to test, because we need
357362306a36Sopenharmony_ci		 * to rely on a signal that has not yet been handled. Let's at
357462306a36Sopenharmony_ci		 * least check that the error code gets propagated through, and
357562306a36Sopenharmony_ci		 * hope that it doesn't break when there is actually a signal :)
357662306a36Sopenharmony_ci		 */
357762306a36Sopenharmony_ci		ret = syscall(__NR_gettid);
357862306a36Sopenharmony_ci		exit(!(ret == -1 && errno == 512));
357962306a36Sopenharmony_ci	}
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci	close(sk_pair[1]);
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	memset(&req, 0, sizeof(req));
358462306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	EXPECT_EQ(kill(pid, SIGUSR1), 0);
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	/*
358962306a36Sopenharmony_ci	 * Make sure the signal really is delivered, which means we're not
359062306a36Sopenharmony_ci	 * stuck in the user notification code any more and the notification
359162306a36Sopenharmony_ci	 * should be dead.
359262306a36Sopenharmony_ci	 */
359362306a36Sopenharmony_ci	EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	resp.id = req.id;
359662306a36Sopenharmony_ci	resp.error = -EPERM;
359762306a36Sopenharmony_ci	resp.val = 0;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
360062306a36Sopenharmony_ci	EXPECT_EQ(errno, ENOENT);
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	memset(&req, 0, sizeof(req));
360362306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	resp.id = req.id;
360662306a36Sopenharmony_ci	resp.error = -512; /* -ERESTARTSYS */
360762306a36Sopenharmony_ci	resp.val = 0;
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
361262306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
361362306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
361462306a36Sopenharmony_ci}
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ciTEST(user_notification_closed_listener)
361762306a36Sopenharmony_ci{
361862306a36Sopenharmony_ci	pid_t pid;
361962306a36Sopenharmony_ci	long ret;
362062306a36Sopenharmony_ci	int status, listener;
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
362362306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
362462306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
362562306a36Sopenharmony_ci	}
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
362862306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
362962306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	/*
363262306a36Sopenharmony_ci	 * Check that we get an ENOSYS when the listener is closed.
363362306a36Sopenharmony_ci	 */
363462306a36Sopenharmony_ci	pid = fork();
363562306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
363662306a36Sopenharmony_ci	if (pid == 0) {
363762306a36Sopenharmony_ci		close(listener);
363862306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
363962306a36Sopenharmony_ci		exit(ret != -1 && errno != ENOSYS);
364062306a36Sopenharmony_ci	}
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	close(listener);
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
364562306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
364662306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
364762306a36Sopenharmony_ci}
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci/*
365062306a36Sopenharmony_ci * Check that a pid in a child namespace still shows up as valid in ours.
365162306a36Sopenharmony_ci */
365262306a36Sopenharmony_ciTEST(user_notification_child_pid_ns)
365362306a36Sopenharmony_ci{
365462306a36Sopenharmony_ci	pid_t pid;
365562306a36Sopenharmony_ci	int status, listener;
365662306a36Sopenharmony_ci	struct seccomp_notif req = {};
365762306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	ASSERT_EQ(unshare(CLONE_NEWUSER | CLONE_NEWPID), 0) {
366062306a36Sopenharmony_ci		if (errno == EINVAL)
366162306a36Sopenharmony_ci			SKIP(return, "kernel missing CLONE_NEWUSER support");
366262306a36Sopenharmony_ci	};
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
366562306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
366662306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	pid = fork();
366962306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci	if (pid == 0)
367262306a36Sopenharmony_ci		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
367562306a36Sopenharmony_ci	EXPECT_EQ(req.pid, pid);
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci	resp.id = req.id;
367862306a36Sopenharmony_ci	resp.error = 0;
367962306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
368462306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
368562306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
368662306a36Sopenharmony_ci	close(listener);
368762306a36Sopenharmony_ci}
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci/*
369062306a36Sopenharmony_ci * Check that a pid in a sibling (i.e. unrelated) namespace shows up as 0, i.e.
369162306a36Sopenharmony_ci * invalid.
369262306a36Sopenharmony_ci */
369362306a36Sopenharmony_ciTEST(user_notification_sibling_pid_ns)
369462306a36Sopenharmony_ci{
369562306a36Sopenharmony_ci	pid_t pid, pid2;
369662306a36Sopenharmony_ci	int status, listener;
369762306a36Sopenharmony_ci	struct seccomp_notif req = {};
369862306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	ASSERT_EQ(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), 0) {
370162306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
370262306a36Sopenharmony_ci	}
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
370562306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
370662306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	pid = fork();
370962306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci	if (pid == 0) {
371262306a36Sopenharmony_ci		ASSERT_EQ(unshare(CLONE_NEWPID), 0);
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci		pid2 = fork();
371562306a36Sopenharmony_ci		ASSERT_GE(pid2, 0);
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci		if (pid2 == 0)
371862306a36Sopenharmony_ci			exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci		EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
372162306a36Sopenharmony_ci		EXPECT_EQ(true, WIFEXITED(status));
372262306a36Sopenharmony_ci		EXPECT_EQ(0, WEXITSTATUS(status));
372362306a36Sopenharmony_ci		exit(WEXITSTATUS(status));
372462306a36Sopenharmony_ci	}
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_ci	/* Create the sibling ns, and sibling in it. */
372762306a36Sopenharmony_ci	ASSERT_EQ(unshare(CLONE_NEWPID), 0) {
372862306a36Sopenharmony_ci		if (errno == EPERM)
372962306a36Sopenharmony_ci			SKIP(return, "CLONE_NEWPID requires CAP_SYS_ADMIN");
373062306a36Sopenharmony_ci	}
373162306a36Sopenharmony_ci	ASSERT_EQ(errno, 0);
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	pid2 = fork();
373462306a36Sopenharmony_ci	ASSERT_GE(pid2, 0);
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	if (pid2 == 0) {
373762306a36Sopenharmony_ci		ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
373862306a36Sopenharmony_ci		/*
373962306a36Sopenharmony_ci		 * The pid should be 0, i.e. the task is in some namespace that
374062306a36Sopenharmony_ci		 * we can't "see".
374162306a36Sopenharmony_ci		 */
374262306a36Sopenharmony_ci		EXPECT_EQ(req.pid, 0);
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci		resp.id = req.id;
374562306a36Sopenharmony_ci		resp.error = 0;
374662306a36Sopenharmony_ci		resp.val = USER_NOTIF_MAGIC;
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci		ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
374962306a36Sopenharmony_ci		exit(0);
375062306a36Sopenharmony_ci	}
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	close(listener);
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
375562306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
375662306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
375962306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
376062306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
376162306a36Sopenharmony_ci}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ciTEST(user_notification_fault_recv)
376462306a36Sopenharmony_ci{
376562306a36Sopenharmony_ci	pid_t pid;
376662306a36Sopenharmony_ci	int status, listener;
376762306a36Sopenharmony_ci	struct seccomp_notif req = {};
376862306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci	ASSERT_EQ(unshare(CLONE_NEWUSER), 0) {
377162306a36Sopenharmony_ci		if (errno == EINVAL)
377262306a36Sopenharmony_ci			SKIP(return, "kernel missing CLONE_NEWUSER support");
377362306a36Sopenharmony_ci	}
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
377662306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
377762306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
377862306a36Sopenharmony_ci
377962306a36Sopenharmony_ci	pid = fork();
378062306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci	if (pid == 0)
378362306a36Sopenharmony_ci		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	/* Do a bad recv() */
378662306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, NULL), -1);
378762306a36Sopenharmony_ci	EXPECT_EQ(errno, EFAULT);
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci	/* We should still be able to receive this notification, though. */
379062306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
379162306a36Sopenharmony_ci	EXPECT_EQ(req.pid, pid);
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	resp.id = req.id;
379462306a36Sopenharmony_ci	resp.error = 0;
379562306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
380062306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
380162306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
380262306a36Sopenharmony_ci}
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ciTEST(seccomp_get_notif_sizes)
380562306a36Sopenharmony_ci{
380662306a36Sopenharmony_ci	struct seccomp_notif_sizes sizes;
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	ASSERT_EQ(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes), 0);
380962306a36Sopenharmony_ci	EXPECT_EQ(sizes.seccomp_notif, sizeof(struct seccomp_notif));
381062306a36Sopenharmony_ci	EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
381162306a36Sopenharmony_ci}
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_ciTEST(user_notification_continue)
381462306a36Sopenharmony_ci{
381562306a36Sopenharmony_ci	pid_t pid;
381662306a36Sopenharmony_ci	long ret;
381762306a36Sopenharmony_ci	int status, listener;
381862306a36Sopenharmony_ci	struct seccomp_notif req = {};
381962306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
382062306a36Sopenharmony_ci	struct pollfd pollfd;
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
382362306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
382462306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
382562306a36Sopenharmony_ci	}
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
382862306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci	pid = fork();
383162306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
383262306a36Sopenharmony_ci
383362306a36Sopenharmony_ci	if (pid == 0) {
383462306a36Sopenharmony_ci		int dup_fd, pipe_fds[2];
383562306a36Sopenharmony_ci		pid_t self;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci		ASSERT_GE(pipe(pipe_fds), 0);
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci		dup_fd = dup(pipe_fds[0]);
384062306a36Sopenharmony_ci		ASSERT_GE(dup_fd, 0);
384162306a36Sopenharmony_ci		EXPECT_NE(pipe_fds[0], dup_fd);
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_ci		self = getpid();
384462306a36Sopenharmony_ci		ASSERT_EQ(filecmp(self, self, pipe_fds[0], dup_fd), 0);
384562306a36Sopenharmony_ci		exit(0);
384662306a36Sopenharmony_ci	}
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_ci	pollfd.fd = listener;
384962306a36Sopenharmony_ci	pollfd.events = POLLIN | POLLOUT;
385062306a36Sopenharmony_ci
385162306a36Sopenharmony_ci	EXPECT_GT(poll(&pollfd, 1, -1), 0);
385262306a36Sopenharmony_ci	EXPECT_EQ(pollfd.revents, POLLIN);
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci	pollfd.fd = listener;
385762306a36Sopenharmony_ci	pollfd.events = POLLIN | POLLOUT;
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	EXPECT_GT(poll(&pollfd, 1, -1), 0);
386062306a36Sopenharmony_ci	EXPECT_EQ(pollfd.revents, POLLOUT);
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci	EXPECT_EQ(req.data.nr, __NR_dup);
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_ci	resp.id = req.id;
386562306a36Sopenharmony_ci	resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE;
386662306a36Sopenharmony_ci
386762306a36Sopenharmony_ci	/*
386862306a36Sopenharmony_ci	 * Verify that setting SECCOMP_USER_NOTIF_FLAG_CONTINUE enforces other
386962306a36Sopenharmony_ci	 * args be set to 0.
387062306a36Sopenharmony_ci	 */
387162306a36Sopenharmony_ci	resp.error = 0;
387262306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
387362306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
387462306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	resp.error = USER_NOTIF_MAGIC;
387762306a36Sopenharmony_ci	resp.val = 0;
387862306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
387962306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci	resp.error = 0;
388262306a36Sopenharmony_ci	resp.val = 0;
388362306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0) {
388462306a36Sopenharmony_ci		if (errno == EINVAL)
388562306a36Sopenharmony_ci			SKIP(goto skip, "Kernel does not support SECCOMP_USER_NOTIF_FLAG_CONTINUE");
388662306a36Sopenharmony_ci	}
388762306a36Sopenharmony_ci
388862306a36Sopenharmony_ciskip:
388962306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
389062306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
389162306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status)) {
389262306a36Sopenharmony_ci		if (WEXITSTATUS(status) == 2) {
389362306a36Sopenharmony_ci			SKIP(return, "Kernel does not support kcmp() syscall");
389462306a36Sopenharmony_ci			return;
389562306a36Sopenharmony_ci		}
389662306a36Sopenharmony_ci	}
389762306a36Sopenharmony_ci}
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ciTEST(user_notification_filter_empty)
390062306a36Sopenharmony_ci{
390162306a36Sopenharmony_ci	pid_t pid;
390262306a36Sopenharmony_ci	long ret;
390362306a36Sopenharmony_ci	int status;
390462306a36Sopenharmony_ci	struct pollfd pollfd;
390562306a36Sopenharmony_ci	struct __clone_args args = {
390662306a36Sopenharmony_ci		.flags = CLONE_FILES,
390762306a36Sopenharmony_ci		.exit_signal = SIGCHLD,
390862306a36Sopenharmony_ci	};
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
391162306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
391262306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
391362306a36Sopenharmony_ci	}
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci	if (__NR_clone3 < 0)
391662306a36Sopenharmony_ci		SKIP(return, "Test not built with clone3 support");
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	pid = sys_clone3(&args, sizeof(args));
391962306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci	if (pid == 0) {
392262306a36Sopenharmony_ci		int listener;
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_ci		listener = user_notif_syscall(__NR_mknodat, SECCOMP_FILTER_FLAG_NEW_LISTENER);
392562306a36Sopenharmony_ci		if (listener < 0)
392662306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci		if (dup2(listener, 200) != 200)
392962306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci		close(listener);
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci		_exit(EXIT_SUCCESS);
393462306a36Sopenharmony_ci	}
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
393762306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
393862306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci	/*
394162306a36Sopenharmony_ci	 * The seccomp filter has become unused so we should be notified once
394262306a36Sopenharmony_ci	 * the kernel gets around to cleaning up task struct.
394362306a36Sopenharmony_ci	 */
394462306a36Sopenharmony_ci	pollfd.fd = 200;
394562306a36Sopenharmony_ci	pollfd.events = POLLHUP;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	EXPECT_GT(poll(&pollfd, 1, 2000), 0);
394862306a36Sopenharmony_ci	EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
394962306a36Sopenharmony_ci}
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_cistatic void *do_thread(void *data)
395262306a36Sopenharmony_ci{
395362306a36Sopenharmony_ci	return NULL;
395462306a36Sopenharmony_ci}
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ciTEST(user_notification_filter_empty_threaded)
395762306a36Sopenharmony_ci{
395862306a36Sopenharmony_ci	pid_t pid;
395962306a36Sopenharmony_ci	long ret;
396062306a36Sopenharmony_ci	int status;
396162306a36Sopenharmony_ci	struct pollfd pollfd;
396262306a36Sopenharmony_ci	struct __clone_args args = {
396362306a36Sopenharmony_ci		.flags = CLONE_FILES,
396462306a36Sopenharmony_ci		.exit_signal = SIGCHLD,
396562306a36Sopenharmony_ci	};
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
396862306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
396962306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
397062306a36Sopenharmony_ci	}
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci	if (__NR_clone3 < 0)
397362306a36Sopenharmony_ci		SKIP(return, "Test not built with clone3 support");
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci	pid = sys_clone3(&args, sizeof(args));
397662306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	if (pid == 0) {
397962306a36Sopenharmony_ci		pid_t pid1, pid2;
398062306a36Sopenharmony_ci		int listener, status;
398162306a36Sopenharmony_ci		pthread_t thread;
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci		listener = user_notif_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
398462306a36Sopenharmony_ci		if (listener < 0)
398562306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci		if (dup2(listener, 200) != 200)
398862306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci		close(listener);
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci		pid1 = fork();
399362306a36Sopenharmony_ci		if (pid1 < 0)
399462306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci		if (pid1 == 0)
399762306a36Sopenharmony_ci			_exit(EXIT_SUCCESS);
399862306a36Sopenharmony_ci
399962306a36Sopenharmony_ci		pid2 = fork();
400062306a36Sopenharmony_ci		if (pid2 < 0)
400162306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci		if (pid2 == 0)
400462306a36Sopenharmony_ci			_exit(EXIT_SUCCESS);
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci		if (pthread_create(&thread, NULL, do_thread, NULL) ||
400762306a36Sopenharmony_ci		    pthread_join(thread, NULL))
400862306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci		if (pthread_create(&thread, NULL, do_thread, NULL) ||
401162306a36Sopenharmony_ci		    pthread_join(thread, NULL))
401262306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci		if (waitpid(pid1, &status, 0) != pid1 || !WIFEXITED(status) ||
401562306a36Sopenharmony_ci		    WEXITSTATUS(status))
401662306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_ci		if (waitpid(pid2, &status, 0) != pid2 || !WIFEXITED(status) ||
401962306a36Sopenharmony_ci		    WEXITSTATUS(status))
402062306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci		exit(EXIT_SUCCESS);
402362306a36Sopenharmony_ci	}
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
402662306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
402762306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_ci	/*
403062306a36Sopenharmony_ci	 * The seccomp filter has become unused so we should be notified once
403162306a36Sopenharmony_ci	 * the kernel gets around to cleaning up task struct.
403262306a36Sopenharmony_ci	 */
403362306a36Sopenharmony_ci	pollfd.fd = 200;
403462306a36Sopenharmony_ci	pollfd.events = POLLHUP;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci	EXPECT_GT(poll(&pollfd, 1, 2000), 0);
403762306a36Sopenharmony_ci	EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
403862306a36Sopenharmony_ci}
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_ciTEST(user_notification_addfd)
404162306a36Sopenharmony_ci{
404262306a36Sopenharmony_ci	pid_t pid;
404362306a36Sopenharmony_ci	long ret;
404462306a36Sopenharmony_ci	int status, listener, memfd, fd, nextfd;
404562306a36Sopenharmony_ci	struct seccomp_notif_addfd addfd = {};
404662306a36Sopenharmony_ci	struct seccomp_notif_addfd_small small = {};
404762306a36Sopenharmony_ci	struct seccomp_notif_addfd_big big = {};
404862306a36Sopenharmony_ci	struct seccomp_notif req = {};
404962306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
405062306a36Sopenharmony_ci	/* 100 ms */
405162306a36Sopenharmony_ci	struct timespec delay = { .tv_nsec = 100000000 };
405262306a36Sopenharmony_ci
405362306a36Sopenharmony_ci	/* There may be arbitrary already-open fds at test start. */
405462306a36Sopenharmony_ci	memfd = memfd_create("test", 0);
405562306a36Sopenharmony_ci	ASSERT_GE(memfd, 0);
405662306a36Sopenharmony_ci	nextfd = memfd + 1;
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
405962306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
406062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
406162306a36Sopenharmony_ci	}
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	/* fd: 4 */
406462306a36Sopenharmony_ci	/* Check that the basic notification machinery works */
406562306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
406662306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
406762306a36Sopenharmony_ci	ASSERT_EQ(listener, nextfd++);
406862306a36Sopenharmony_ci
406962306a36Sopenharmony_ci	pid = fork();
407062306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	if (pid == 0) {
407362306a36Sopenharmony_ci		/* fds will be added and this value is expected */
407462306a36Sopenharmony_ci		if (syscall(__NR_getppid) != USER_NOTIF_MAGIC)
407562306a36Sopenharmony_ci			exit(1);
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci		/* Atomic addfd+send is received here. Check it is a valid fd */
407862306a36Sopenharmony_ci		if (fcntl(syscall(__NR_getppid), F_GETFD) == -1)
407962306a36Sopenharmony_ci			exit(1);
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ci		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
408262306a36Sopenharmony_ci	}
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	addfd.srcfd = memfd;
408762306a36Sopenharmony_ci	addfd.newfd = 0;
408862306a36Sopenharmony_ci	addfd.id = req.id;
408962306a36Sopenharmony_ci	addfd.flags = 0x0;
409062306a36Sopenharmony_ci
409162306a36Sopenharmony_ci	/* Verify bad newfd_flags cannot be set */
409262306a36Sopenharmony_ci	addfd.newfd_flags = ~O_CLOEXEC;
409362306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
409462306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
409562306a36Sopenharmony_ci	addfd.newfd_flags = O_CLOEXEC;
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	/* Verify bad flags cannot be set */
409862306a36Sopenharmony_ci	addfd.flags = 0xff;
409962306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
410062306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
410162306a36Sopenharmony_ci	addfd.flags = 0;
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_ci	/* Verify that remote_fd cannot be set without setting flags */
410462306a36Sopenharmony_ci	addfd.newfd = 1;
410562306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
410662306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
410762306a36Sopenharmony_ci	addfd.newfd = 0;
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_ci	/* Verify small size cannot be set */
411062306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_SMALL, &small), -1);
411162306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
411262306a36Sopenharmony_ci
411362306a36Sopenharmony_ci	/* Verify we can't send bits filled in unknown buffer area */
411462306a36Sopenharmony_ci	memset(&big, 0xAA, sizeof(big));
411562306a36Sopenharmony_ci	big.addfd = addfd;
411662306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big), -1);
411762306a36Sopenharmony_ci	EXPECT_EQ(errno, E2BIG);
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci	/* Verify we can set an arbitrary remote fd */
412162306a36Sopenharmony_ci	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
412262306a36Sopenharmony_ci	EXPECT_EQ(fd, nextfd++);
412362306a36Sopenharmony_ci	EXPECT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	/* Verify we can set an arbitrary remote fd with large size */
412662306a36Sopenharmony_ci	memset(&big, 0x0, sizeof(big));
412762306a36Sopenharmony_ci	big.addfd = addfd;
412862306a36Sopenharmony_ci	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big);
412962306a36Sopenharmony_ci	EXPECT_EQ(fd, nextfd++);
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci	/* Verify we can set a specific remote fd */
413262306a36Sopenharmony_ci	addfd.newfd = 42;
413362306a36Sopenharmony_ci	addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
413462306a36Sopenharmony_ci	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
413562306a36Sopenharmony_ci	EXPECT_EQ(fd, 42);
413662306a36Sopenharmony_ci	EXPECT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ci	/* Resume syscall */
413962306a36Sopenharmony_ci	resp.id = req.id;
414062306a36Sopenharmony_ci	resp.error = 0;
414162306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
414262306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci	/*
414562306a36Sopenharmony_ci	 * This sets the ID of the ADD FD to the last request plus 1. The
414662306a36Sopenharmony_ci	 * notification ID increments 1 per notification.
414762306a36Sopenharmony_ci	 */
414862306a36Sopenharmony_ci	addfd.id = req.id + 1;
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_ci	/* This spins until the underlying notification is generated */
415162306a36Sopenharmony_ci	while (ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd) != -1 &&
415262306a36Sopenharmony_ci	       errno != -EINPROGRESS)
415362306a36Sopenharmony_ci		nanosleep(&delay, NULL);
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	memset(&req, 0, sizeof(req));
415662306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
415762306a36Sopenharmony_ci	ASSERT_EQ(addfd.id, req.id);
415862306a36Sopenharmony_ci
415962306a36Sopenharmony_ci	/* Verify we can do an atomic addfd and send */
416062306a36Sopenharmony_ci	addfd.newfd = 0;
416162306a36Sopenharmony_ci	addfd.flags = SECCOMP_ADDFD_FLAG_SEND;
416262306a36Sopenharmony_ci	fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
416362306a36Sopenharmony_ci	/*
416462306a36Sopenharmony_ci	 * Child has earlier "low" fds and now 42, so we expect the next
416562306a36Sopenharmony_ci	 * lowest available fd to be assigned here.
416662306a36Sopenharmony_ci	 */
416762306a36Sopenharmony_ci	EXPECT_EQ(fd, nextfd++);
416862306a36Sopenharmony_ci	ASSERT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	/*
417162306a36Sopenharmony_ci	 * This sets the ID of the ADD FD to the last request plus 1. The
417262306a36Sopenharmony_ci	 * notification ID increments 1 per notification.
417362306a36Sopenharmony_ci	 */
417462306a36Sopenharmony_ci	addfd.id = req.id + 1;
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	/* This spins until the underlying notification is generated */
417762306a36Sopenharmony_ci	while (ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd) != -1 &&
417862306a36Sopenharmony_ci	       errno != -EINPROGRESS)
417962306a36Sopenharmony_ci		nanosleep(&delay, NULL);
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	memset(&req, 0, sizeof(req));
418262306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
418362306a36Sopenharmony_ci	ASSERT_EQ(addfd.id, req.id);
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_ci	resp.id = req.id;
418662306a36Sopenharmony_ci	resp.error = 0;
418762306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
418862306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci	/* Wait for child to finish. */
419162306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
419262306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
419362306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	close(memfd);
419662306a36Sopenharmony_ci}
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ciTEST(user_notification_addfd_rlimit)
419962306a36Sopenharmony_ci{
420062306a36Sopenharmony_ci	pid_t pid;
420162306a36Sopenharmony_ci	long ret;
420262306a36Sopenharmony_ci	int status, listener, memfd;
420362306a36Sopenharmony_ci	struct seccomp_notif_addfd addfd = {};
420462306a36Sopenharmony_ci	struct seccomp_notif req = {};
420562306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
420662306a36Sopenharmony_ci	const struct rlimit lim = {
420762306a36Sopenharmony_ci		.rlim_cur	= 0,
420862306a36Sopenharmony_ci		.rlim_max	= 0,
420962306a36Sopenharmony_ci	};
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci	memfd = memfd_create("test", 0);
421262306a36Sopenharmony_ci	ASSERT_GE(memfd, 0);
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
421562306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
421662306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
421762306a36Sopenharmony_ci	}
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_ci	/* Check that the basic notification machinery works */
422062306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
422162306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
422262306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
422362306a36Sopenharmony_ci
422462306a36Sopenharmony_ci	pid = fork();
422562306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	if (pid == 0)
422862306a36Sopenharmony_ci		exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	ASSERT_EQ(prlimit(pid, RLIMIT_NOFILE, &lim, NULL), 0);
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_ci	addfd.srcfd = memfd;
423662306a36Sopenharmony_ci	addfd.newfd_flags = O_CLOEXEC;
423762306a36Sopenharmony_ci	addfd.newfd = 0;
423862306a36Sopenharmony_ci	addfd.id = req.id;
423962306a36Sopenharmony_ci	addfd.flags = 0;
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci	/* Should probably spot check /proc/sys/fs/file-nr */
424262306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
424362306a36Sopenharmony_ci	EXPECT_EQ(errno, EMFILE);
424462306a36Sopenharmony_ci
424562306a36Sopenharmony_ci	addfd.flags = SECCOMP_ADDFD_FLAG_SEND;
424662306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
424762306a36Sopenharmony_ci	EXPECT_EQ(errno, EMFILE);
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	addfd.newfd = 100;
425062306a36Sopenharmony_ci	addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
425162306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
425262306a36Sopenharmony_ci	EXPECT_EQ(errno, EBADF);
425362306a36Sopenharmony_ci
425462306a36Sopenharmony_ci	resp.id = req.id;
425562306a36Sopenharmony_ci	resp.error = 0;
425662306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci	/* Wait for child to finish. */
426162306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
426262306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
426362306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	close(memfd);
426662306a36Sopenharmony_ci}
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci#ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP
426962306a36Sopenharmony_ci#define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0)
427062306a36Sopenharmony_ci#define SECCOMP_IOCTL_NOTIF_SET_FLAGS  SECCOMP_IOW(4, __u64)
427162306a36Sopenharmony_ci#endif
427262306a36Sopenharmony_ci
427362306a36Sopenharmony_ciTEST(user_notification_sync)
427462306a36Sopenharmony_ci{
427562306a36Sopenharmony_ci	struct seccomp_notif req = {};
427662306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
427762306a36Sopenharmony_ci	int status, listener;
427862306a36Sopenharmony_ci	pid_t pid;
427962306a36Sopenharmony_ci	long ret;
428062306a36Sopenharmony_ci
428162306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
428262306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
428362306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
428462306a36Sopenharmony_ci	}
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
428762306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
428862306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci	/* Try to set invalid flags. */
429162306a36Sopenharmony_ci	EXPECT_SYSCALL_RETURN(-EINVAL,
429262306a36Sopenharmony_ci		ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS, 0xffffffff, 0));
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS,
429562306a36Sopenharmony_ci			SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP, 0), 0);
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci	pid = fork();
429862306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
429962306a36Sopenharmony_ci	if (pid == 0) {
430062306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
430162306a36Sopenharmony_ci		ASSERT_EQ(ret, USER_NOTIF_MAGIC) {
430262306a36Sopenharmony_ci			_exit(1);
430362306a36Sopenharmony_ci		}
430462306a36Sopenharmony_ci		_exit(0);
430562306a36Sopenharmony_ci	}
430662306a36Sopenharmony_ci
430762306a36Sopenharmony_ci	req.pid = 0;
430862306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci	ASSERT_EQ(req.data.nr,  __NR_getppid);
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci	resp.id = req.id;
431362306a36Sopenharmony_ci	resp.error = 0;
431462306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
431562306a36Sopenharmony_ci	resp.flags = 0;
431662306a36Sopenharmony_ci	ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	ASSERT_EQ(waitpid(pid, &status, 0), pid);
431962306a36Sopenharmony_ci	ASSERT_EQ(status, 0);
432062306a36Sopenharmony_ci}
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci
432362306a36Sopenharmony_ci/* Make sure PTRACE_O_SUSPEND_SECCOMP requires CAP_SYS_ADMIN. */
432462306a36Sopenharmony_ciFIXTURE(O_SUSPEND_SECCOMP) {
432562306a36Sopenharmony_ci	pid_t pid;
432662306a36Sopenharmony_ci};
432762306a36Sopenharmony_ci
432862306a36Sopenharmony_ciFIXTURE_SETUP(O_SUSPEND_SECCOMP)
432962306a36Sopenharmony_ci{
433062306a36Sopenharmony_ci	ERRNO_FILTER(block_read, E2BIG);
433162306a36Sopenharmony_ci	cap_value_t cap_list[] = { CAP_SYS_ADMIN };
433262306a36Sopenharmony_ci	cap_t caps;
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	self->pid = 0;
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	/* make sure we don't have CAP_SYS_ADMIN */
433762306a36Sopenharmony_ci	caps = cap_get_proc();
433862306a36Sopenharmony_ci	ASSERT_NE(NULL, caps);
433962306a36Sopenharmony_ci	ASSERT_EQ(0, cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_CLEAR));
434062306a36Sopenharmony_ci	ASSERT_EQ(0, cap_set_proc(caps));
434162306a36Sopenharmony_ci	cap_free(caps);
434262306a36Sopenharmony_ci
434362306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
434462306a36Sopenharmony_ci	ASSERT_EQ(0, prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_block_read));
434562306a36Sopenharmony_ci
434662306a36Sopenharmony_ci	self->pid = fork();
434762306a36Sopenharmony_ci	ASSERT_GE(self->pid, 0);
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	if (self->pid == 0) {
435062306a36Sopenharmony_ci		while (1)
435162306a36Sopenharmony_ci			pause();
435262306a36Sopenharmony_ci		_exit(127);
435362306a36Sopenharmony_ci	}
435462306a36Sopenharmony_ci}
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ciFIXTURE_TEARDOWN(O_SUSPEND_SECCOMP)
435762306a36Sopenharmony_ci{
435862306a36Sopenharmony_ci	if (self->pid)
435962306a36Sopenharmony_ci		kill(self->pid, SIGKILL);
436062306a36Sopenharmony_ci}
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ciTEST_F(O_SUSPEND_SECCOMP, setoptions)
436362306a36Sopenharmony_ci{
436462306a36Sopenharmony_ci	int wstatus;
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	ASSERT_EQ(0, ptrace(PTRACE_ATTACH, self->pid, NULL, 0));
436762306a36Sopenharmony_ci	ASSERT_EQ(self->pid, wait(&wstatus));
436862306a36Sopenharmony_ci	ASSERT_EQ(-1, ptrace(PTRACE_SETOPTIONS, self->pid, NULL, PTRACE_O_SUSPEND_SECCOMP));
436962306a36Sopenharmony_ci	if (errno == EINVAL)
437062306a36Sopenharmony_ci		SKIP(return, "Kernel does not support PTRACE_O_SUSPEND_SECCOMP (missing CONFIG_CHECKPOINT_RESTORE?)");
437162306a36Sopenharmony_ci	ASSERT_EQ(EPERM, errno);
437262306a36Sopenharmony_ci}
437362306a36Sopenharmony_ci
437462306a36Sopenharmony_ciTEST_F(O_SUSPEND_SECCOMP, seize)
437562306a36Sopenharmony_ci{
437662306a36Sopenharmony_ci	int ret;
437762306a36Sopenharmony_ci
437862306a36Sopenharmony_ci	ret = ptrace(PTRACE_SEIZE, self->pid, NULL, PTRACE_O_SUSPEND_SECCOMP);
437962306a36Sopenharmony_ci	ASSERT_EQ(-1, ret);
438062306a36Sopenharmony_ci	if (errno == EINVAL)
438162306a36Sopenharmony_ci		SKIP(return, "Kernel does not support PTRACE_O_SUSPEND_SECCOMP (missing CONFIG_CHECKPOINT_RESTORE?)");
438262306a36Sopenharmony_ci	ASSERT_EQ(EPERM, errno);
438362306a36Sopenharmony_ci}
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci/*
438662306a36Sopenharmony_ci * get_nth - Get the nth, space separated entry in a file.
438762306a36Sopenharmony_ci *
438862306a36Sopenharmony_ci * Returns the length of the read field.
438962306a36Sopenharmony_ci * Throws error if field is zero-lengthed.
439062306a36Sopenharmony_ci */
439162306a36Sopenharmony_cistatic ssize_t get_nth(struct __test_metadata *_metadata, const char *path,
439262306a36Sopenharmony_ci		     const unsigned int position, char **entry)
439362306a36Sopenharmony_ci{
439462306a36Sopenharmony_ci	char *line = NULL;
439562306a36Sopenharmony_ci	unsigned int i;
439662306a36Sopenharmony_ci	ssize_t nread;
439762306a36Sopenharmony_ci	size_t len = 0;
439862306a36Sopenharmony_ci	FILE *f;
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	f = fopen(path, "r");
440162306a36Sopenharmony_ci	ASSERT_NE(f, NULL) {
440262306a36Sopenharmony_ci		TH_LOG("Could not open %s: %s", path, strerror(errno));
440362306a36Sopenharmony_ci	}
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci	for (i = 0; i < position; i++) {
440662306a36Sopenharmony_ci		nread = getdelim(&line, &len, ' ', f);
440762306a36Sopenharmony_ci		ASSERT_GE(nread, 0) {
440862306a36Sopenharmony_ci			TH_LOG("Failed to read %d entry in file %s", i, path);
440962306a36Sopenharmony_ci		}
441062306a36Sopenharmony_ci	}
441162306a36Sopenharmony_ci	fclose(f);
441262306a36Sopenharmony_ci
441362306a36Sopenharmony_ci	ASSERT_GT(nread, 0) {
441462306a36Sopenharmony_ci		TH_LOG("Entry in file %s had zero length", path);
441562306a36Sopenharmony_ci	}
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	*entry = line;
441862306a36Sopenharmony_ci	return nread - 1;
441962306a36Sopenharmony_ci}
442062306a36Sopenharmony_ci
442162306a36Sopenharmony_ci/* For a given PID, get the task state (D, R, etc...) */
442262306a36Sopenharmony_cistatic char get_proc_stat(struct __test_metadata *_metadata, pid_t pid)
442362306a36Sopenharmony_ci{
442462306a36Sopenharmony_ci	char proc_path[100] = {0};
442562306a36Sopenharmony_ci	char status;
442662306a36Sopenharmony_ci	char *line;
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_ci	snprintf(proc_path, sizeof(proc_path), "/proc/%d/stat", pid);
442962306a36Sopenharmony_ci	ASSERT_EQ(get_nth(_metadata, proc_path, 3, &line), 1);
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_ci	status = *line;
443262306a36Sopenharmony_ci	free(line);
443362306a36Sopenharmony_ci
443462306a36Sopenharmony_ci	return status;
443562306a36Sopenharmony_ci}
443662306a36Sopenharmony_ci
443762306a36Sopenharmony_ciTEST(user_notification_fifo)
443862306a36Sopenharmony_ci{
443962306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
444062306a36Sopenharmony_ci	struct seccomp_notif req = {};
444162306a36Sopenharmony_ci	int i, status, listener;
444262306a36Sopenharmony_ci	pid_t pid, pids[3];
444362306a36Sopenharmony_ci	__u64 baseid;
444462306a36Sopenharmony_ci	long ret;
444562306a36Sopenharmony_ci	/* 100 ms */
444662306a36Sopenharmony_ci	struct timespec delay = { .tv_nsec = 100000000 };
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
444962306a36Sopenharmony_ci	ASSERT_EQ(0, ret) {
445062306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
445162306a36Sopenharmony_ci	}
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci	/* Setup a listener */
445462306a36Sopenharmony_ci	listener = user_notif_syscall(__NR_getppid,
445562306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_NEW_LISTENER);
445662306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
445762306a36Sopenharmony_ci
445862306a36Sopenharmony_ci	pid = fork();
445962306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci	if (pid == 0) {
446262306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
446362306a36Sopenharmony_ci		exit(ret != USER_NOTIF_MAGIC);
446462306a36Sopenharmony_ci	}
446562306a36Sopenharmony_ci
446662306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
446762306a36Sopenharmony_ci	baseid = req.id + 1;
446862306a36Sopenharmony_ci
446962306a36Sopenharmony_ci	resp.id = req.id;
447062306a36Sopenharmony_ci	resp.error = 0;
447162306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci	/* check that we make sure flags == 0 */
447462306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
447762306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
447862306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
447962306a36Sopenharmony_ci
448062306a36Sopenharmony_ci	/* Start children, and generate notifications */
448162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pids); i++) {
448262306a36Sopenharmony_ci		pid = fork();
448362306a36Sopenharmony_ci		if (pid == 0) {
448462306a36Sopenharmony_ci			ret = syscall(__NR_getppid);
448562306a36Sopenharmony_ci			exit(ret != USER_NOTIF_MAGIC);
448662306a36Sopenharmony_ci		}
448762306a36Sopenharmony_ci		pids[i] = pid;
448862306a36Sopenharmony_ci	}
448962306a36Sopenharmony_ci
449062306a36Sopenharmony_ci	/* This spins until all of the children are sleeping */
449162306a36Sopenharmony_cirestart_wait:
449262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pids); i++) {
449362306a36Sopenharmony_ci		if (get_proc_stat(_metadata, pids[i]) != 'S') {
449462306a36Sopenharmony_ci			nanosleep(&delay, NULL);
449562306a36Sopenharmony_ci			goto restart_wait;
449662306a36Sopenharmony_ci		}
449762306a36Sopenharmony_ci	}
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	/* Read the notifications in order (and respond) */
450062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pids); i++) {
450162306a36Sopenharmony_ci		memset(&req, 0, sizeof(req));
450262306a36Sopenharmony_ci		EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
450362306a36Sopenharmony_ci		EXPECT_EQ(req.id, baseid + i);
450462306a36Sopenharmony_ci		resp.id = req.id;
450562306a36Sopenharmony_ci		EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
450662306a36Sopenharmony_ci	}
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	/* Make sure notifications were received */
450962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pids); i++) {
451062306a36Sopenharmony_ci		EXPECT_EQ(waitpid(pids[i], &status, 0), pids[i]);
451162306a36Sopenharmony_ci		EXPECT_EQ(true, WIFEXITED(status));
451262306a36Sopenharmony_ci		EXPECT_EQ(0, WEXITSTATUS(status));
451362306a36Sopenharmony_ci	}
451462306a36Sopenharmony_ci}
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci/* get_proc_syscall - Get the syscall in progress for a given pid
451762306a36Sopenharmony_ci *
451862306a36Sopenharmony_ci * Returns the current syscall number for a given process
451962306a36Sopenharmony_ci * Returns -1 if not in syscall (running or blocked)
452062306a36Sopenharmony_ci */
452162306a36Sopenharmony_cistatic long get_proc_syscall(struct __test_metadata *_metadata, int pid)
452262306a36Sopenharmony_ci{
452362306a36Sopenharmony_ci	char proc_path[100] = {0};
452462306a36Sopenharmony_ci	long ret = -1;
452562306a36Sopenharmony_ci	ssize_t nread;
452662306a36Sopenharmony_ci	char *line;
452762306a36Sopenharmony_ci
452862306a36Sopenharmony_ci	snprintf(proc_path, sizeof(proc_path), "/proc/%d/syscall", pid);
452962306a36Sopenharmony_ci	nread = get_nth(_metadata, proc_path, 1, &line);
453062306a36Sopenharmony_ci	ASSERT_GT(nread, 0);
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	if (!strncmp("running", line, MIN(7, nread)))
453362306a36Sopenharmony_ci		ret = strtol(line, NULL, 16);
453462306a36Sopenharmony_ci
453562306a36Sopenharmony_ci	free(line);
453662306a36Sopenharmony_ci	return ret;
453762306a36Sopenharmony_ci}
453862306a36Sopenharmony_ci
453962306a36Sopenharmony_ci/* Ensure non-fatal signals prior to receive are unmodified */
454062306a36Sopenharmony_ciTEST(user_notification_wait_killable_pre_notification)
454162306a36Sopenharmony_ci{
454262306a36Sopenharmony_ci	struct sigaction new_action = {
454362306a36Sopenharmony_ci		.sa_handler = signal_handler,
454462306a36Sopenharmony_ci	};
454562306a36Sopenharmony_ci	int listener, status, sk_pair[2];
454662306a36Sopenharmony_ci	pid_t pid;
454762306a36Sopenharmony_ci	long ret;
454862306a36Sopenharmony_ci	char c;
454962306a36Sopenharmony_ci	/* 100 ms */
455062306a36Sopenharmony_ci	struct timespec delay = { .tv_nsec = 100000000 };
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci	ASSERT_EQ(sigemptyset(&new_action.sa_mask), 0);
455362306a36Sopenharmony_ci
455462306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
455562306a36Sopenharmony_ci	ASSERT_EQ(0, ret)
455662306a36Sopenharmony_ci	{
455762306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
455862306a36Sopenharmony_ci	}
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	listener = user_notif_syscall(
456362306a36Sopenharmony_ci		__NR_getppid, SECCOMP_FILTER_FLAG_NEW_LISTENER |
456462306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV);
456562306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
456662306a36Sopenharmony_ci
456762306a36Sopenharmony_ci	/*
456862306a36Sopenharmony_ci	 * Check that we can kill the process with SIGUSR1 prior to receiving
456962306a36Sopenharmony_ci	 * the notification. SIGUSR1 is wired up to a custom signal handler,
457062306a36Sopenharmony_ci	 * and make sure it gets called.
457162306a36Sopenharmony_ci	 */
457262306a36Sopenharmony_ci	pid = fork();
457362306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
457462306a36Sopenharmony_ci
457562306a36Sopenharmony_ci	if (pid == 0) {
457662306a36Sopenharmony_ci		close(sk_pair[0]);
457762306a36Sopenharmony_ci		handled = sk_pair[1];
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci		/* Setup the non-fatal sigaction without SA_RESTART */
458062306a36Sopenharmony_ci		if (sigaction(SIGUSR1, &new_action, NULL)) {
458162306a36Sopenharmony_ci			perror("sigaction");
458262306a36Sopenharmony_ci			exit(1);
458362306a36Sopenharmony_ci		}
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
458662306a36Sopenharmony_ci		/* Make sure we got a return from a signal interruption */
458762306a36Sopenharmony_ci		exit(ret != -1 || errno != EINTR);
458862306a36Sopenharmony_ci	}
458962306a36Sopenharmony_ci
459062306a36Sopenharmony_ci	/*
459162306a36Sopenharmony_ci	 * Make sure we've gotten to the seccomp user notification wait
459262306a36Sopenharmony_ci	 * from getppid prior to sending any signals
459362306a36Sopenharmony_ci	 */
459462306a36Sopenharmony_ci	while (get_proc_syscall(_metadata, pid) != __NR_getppid &&
459562306a36Sopenharmony_ci	       get_proc_stat(_metadata, pid) != 'S')
459662306a36Sopenharmony_ci		nanosleep(&delay, NULL);
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ci	/* Send non-fatal kill signal */
459962306a36Sopenharmony_ci	EXPECT_EQ(kill(pid, SIGUSR1), 0);
460062306a36Sopenharmony_ci
460162306a36Sopenharmony_ci	/* wait for process to exit (exit checks for EINTR) */
460262306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
460362306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
460462306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
460562306a36Sopenharmony_ci
460662306a36Sopenharmony_ci	EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
460762306a36Sopenharmony_ci}
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci/* Ensure non-fatal signals after receive are blocked */
461062306a36Sopenharmony_ciTEST(user_notification_wait_killable)
461162306a36Sopenharmony_ci{
461262306a36Sopenharmony_ci	struct sigaction new_action = {
461362306a36Sopenharmony_ci		.sa_handler = signal_handler,
461462306a36Sopenharmony_ci	};
461562306a36Sopenharmony_ci	struct seccomp_notif_resp resp = {};
461662306a36Sopenharmony_ci	struct seccomp_notif req = {};
461762306a36Sopenharmony_ci	int listener, status, sk_pair[2];
461862306a36Sopenharmony_ci	pid_t pid;
461962306a36Sopenharmony_ci	long ret;
462062306a36Sopenharmony_ci	char c;
462162306a36Sopenharmony_ci	/* 100 ms */
462262306a36Sopenharmony_ci	struct timespec delay = { .tv_nsec = 100000000 };
462362306a36Sopenharmony_ci
462462306a36Sopenharmony_ci	ASSERT_EQ(sigemptyset(&new_action.sa_mask), 0);
462562306a36Sopenharmony_ci
462662306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
462762306a36Sopenharmony_ci	ASSERT_EQ(0, ret)
462862306a36Sopenharmony_ci	{
462962306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
463062306a36Sopenharmony_ci	}
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci	ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci	listener = user_notif_syscall(
463562306a36Sopenharmony_ci		__NR_getppid, SECCOMP_FILTER_FLAG_NEW_LISTENER |
463662306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV);
463762306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci	pid = fork();
464062306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
464162306a36Sopenharmony_ci
464262306a36Sopenharmony_ci	if (pid == 0) {
464362306a36Sopenharmony_ci		close(sk_pair[0]);
464462306a36Sopenharmony_ci		handled = sk_pair[1];
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_ci		/* Setup the sigaction without SA_RESTART */
464762306a36Sopenharmony_ci		if (sigaction(SIGUSR1, &new_action, NULL)) {
464862306a36Sopenharmony_ci			perror("sigaction");
464962306a36Sopenharmony_ci			exit(1);
465062306a36Sopenharmony_ci		}
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci		/* Make sure that the syscall is completed (no EINTR) */
465362306a36Sopenharmony_ci		ret = syscall(__NR_getppid);
465462306a36Sopenharmony_ci		exit(ret != USER_NOTIF_MAGIC);
465562306a36Sopenharmony_ci	}
465662306a36Sopenharmony_ci
465762306a36Sopenharmony_ci	/*
465862306a36Sopenharmony_ci	 * Get the notification, to make move the notifying process into a
465962306a36Sopenharmony_ci	 * non-preemptible (TASK_KILLABLE) state.
466062306a36Sopenharmony_ci	 */
466162306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
466262306a36Sopenharmony_ci	/* Send non-fatal kill signal */
466362306a36Sopenharmony_ci	EXPECT_EQ(kill(pid, SIGUSR1), 0);
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	/*
466662306a36Sopenharmony_ci	 * Make sure the task enters moves to TASK_KILLABLE by waiting for
466762306a36Sopenharmony_ci	 * D (Disk Sleep) state after receiving non-fatal signal.
466862306a36Sopenharmony_ci	 */
466962306a36Sopenharmony_ci	while (get_proc_stat(_metadata, pid) != 'D')
467062306a36Sopenharmony_ci		nanosleep(&delay, NULL);
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci	resp.id = req.id;
467362306a36Sopenharmony_ci	resp.val = USER_NOTIF_MAGIC;
467462306a36Sopenharmony_ci	/* Make sure the notification is found and able to be replied to */
467562306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_ci	/*
467862306a36Sopenharmony_ci	 * Make sure that the signal handler does get called once we're back in
467962306a36Sopenharmony_ci	 * userspace.
468062306a36Sopenharmony_ci	 */
468162306a36Sopenharmony_ci	EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
468262306a36Sopenharmony_ci	/* wait for process to exit (exit checks for USER_NOTIF_MAGIC) */
468362306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
468462306a36Sopenharmony_ci	EXPECT_EQ(true, WIFEXITED(status));
468562306a36Sopenharmony_ci	EXPECT_EQ(0, WEXITSTATUS(status));
468662306a36Sopenharmony_ci}
468762306a36Sopenharmony_ci
468862306a36Sopenharmony_ci/* Ensure fatal signals after receive are not blocked */
468962306a36Sopenharmony_ciTEST(user_notification_wait_killable_fatal)
469062306a36Sopenharmony_ci{
469162306a36Sopenharmony_ci	struct seccomp_notif req = {};
469262306a36Sopenharmony_ci	int listener, status;
469362306a36Sopenharmony_ci	pid_t pid;
469462306a36Sopenharmony_ci	long ret;
469562306a36Sopenharmony_ci	/* 100 ms */
469662306a36Sopenharmony_ci	struct timespec delay = { .tv_nsec = 100000000 };
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
469962306a36Sopenharmony_ci	ASSERT_EQ(0, ret)
470062306a36Sopenharmony_ci	{
470162306a36Sopenharmony_ci		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
470262306a36Sopenharmony_ci	}
470362306a36Sopenharmony_ci
470462306a36Sopenharmony_ci	listener = user_notif_syscall(
470562306a36Sopenharmony_ci		__NR_getppid, SECCOMP_FILTER_FLAG_NEW_LISTENER |
470662306a36Sopenharmony_ci				      SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV);
470762306a36Sopenharmony_ci	ASSERT_GE(listener, 0);
470862306a36Sopenharmony_ci
470962306a36Sopenharmony_ci	pid = fork();
471062306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_ci	if (pid == 0) {
471362306a36Sopenharmony_ci		/* This should never complete as it should get a SIGTERM */
471462306a36Sopenharmony_ci		syscall(__NR_getppid);
471562306a36Sopenharmony_ci		exit(1);
471662306a36Sopenharmony_ci	}
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci	while (get_proc_stat(_metadata, pid) != 'S')
471962306a36Sopenharmony_ci		nanosleep(&delay, NULL);
472062306a36Sopenharmony_ci
472162306a36Sopenharmony_ci	/*
472262306a36Sopenharmony_ci	 * Get the notification, to make move the notifying process into a
472362306a36Sopenharmony_ci	 * non-preemptible (TASK_KILLABLE) state.
472462306a36Sopenharmony_ci	 */
472562306a36Sopenharmony_ci	EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
472662306a36Sopenharmony_ci	/* Kill the process with a fatal signal */
472762306a36Sopenharmony_ci	EXPECT_EQ(kill(pid, SIGTERM), 0);
472862306a36Sopenharmony_ci
472962306a36Sopenharmony_ci	/*
473062306a36Sopenharmony_ci	 * Wait for the process to exit, and make sure the process terminated
473162306a36Sopenharmony_ci	 * due to the SIGTERM signal.
473262306a36Sopenharmony_ci	 */
473362306a36Sopenharmony_ci	EXPECT_EQ(waitpid(pid, &status, 0), pid);
473462306a36Sopenharmony_ci	EXPECT_EQ(true, WIFSIGNALED(status));
473562306a36Sopenharmony_ci	EXPECT_EQ(SIGTERM, WTERMSIG(status));
473662306a36Sopenharmony_ci}
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci/*
473962306a36Sopenharmony_ci * TODO:
474062306a36Sopenharmony_ci * - expand NNP testing
474162306a36Sopenharmony_ci * - better arch-specific TRACE and TRAP handlers.
474262306a36Sopenharmony_ci * - endianness checking when appropriate
474362306a36Sopenharmony_ci * - 64-bit arg prodding
474462306a36Sopenharmony_ci * - arch value testing (x86 modes especially)
474562306a36Sopenharmony_ci * - verify that FILTER_FLAG_LOG filters generate log messages
474662306a36Sopenharmony_ci * - verify that RET_LOG generates log messages
474762306a36Sopenharmony_ci */
474862306a36Sopenharmony_ci
474962306a36Sopenharmony_ciTEST_HARNESS_MAIN
4750