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, ®s, 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