1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Test PR_GET_SECCOMP and PR_SET_SECCOMP of prctl(2). 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * - If PR_SET_SECCOMP sets the SECCOMP_MODE_STRICT for the calling thread, 13f08c3bdfSopenharmony_ci * the only system call that the thread is permitted to make are read(2), 14f08c3bdfSopenharmony_ci * write(2),_exit(2)(but not exit_group(2)), and sigreturn(2). Other 15f08c3bdfSopenharmony_ci * system calls result in the delivery of a SIGKILL signal. This operation 16f08c3bdfSopenharmony_ci * is available only if the kernel is configured with CONFIG_SECCOMP enabled. 17f08c3bdfSopenharmony_ci * 18f08c3bdfSopenharmony_ci * - If PR_SET_SECCOMP sets the SECCOMP_MODE_FILTER for the calling thread, 19f08c3bdfSopenharmony_ci * the system calls allowed are defined by a pointer to a Berkeley Packet 20f08c3bdfSopenharmony_ci * Filter. Other system calls result int the delivery of a SIGSYS signal 21f08c3bdfSopenharmony_ci * with SECCOMP_RET_KILL. The SECCOMP_SET_MODE_FILTER operation is available 22f08c3bdfSopenharmony_ci * only if the kernel is configured with CONFIG_SECCOMP_FILTER enabled. 23f08c3bdfSopenharmony_ci * 24f08c3bdfSopenharmony_ci * - If SECCOMP_MODE_FILTER filters permit fork(2), then the seccomp mode 25f08c3bdfSopenharmony_ci * is inherited by children created by fork(2). 26f08c3bdfSopenharmony_ci */ 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#include <errno.h> 29f08c3bdfSopenharmony_ci#include <signal.h> 30f08c3bdfSopenharmony_ci#include <sys/prctl.h> 31f08c3bdfSopenharmony_ci#include <sys/wait.h> 32f08c3bdfSopenharmony_ci#include <sys/types.h> 33f08c3bdfSopenharmony_ci#include <linux/filter.h> 34f08c3bdfSopenharmony_ci#include <unistd.h> 35f08c3bdfSopenharmony_ci#include <stdlib.h> 36f08c3bdfSopenharmony_ci#include <stddef.h> 37f08c3bdfSopenharmony_ci#include "tst_test.h" 38f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 39f08c3bdfSopenharmony_ci#include "lapi/prctl.h" 40f08c3bdfSopenharmony_ci#include "config.h" 41f08c3bdfSopenharmony_ci#include "lapi/seccomp.h" 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#define FNAME "filename" 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_cistatic const struct sock_filter strict_filter[] = { 46f08c3bdfSopenharmony_ci BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_waitid, 7, 0), 49f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_rt_sigprocmask, 6, 0), 50f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), 51f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), 52f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_wait4, 3, 0), 53f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_write, 2, 0), 54f08c3bdfSopenharmony_ci BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_clone, 1, 0), 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), 57f08c3bdfSopenharmony_ci BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) 58f08c3bdfSopenharmony_ci}; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_cistatic const struct sock_fprog strict = { 61f08c3bdfSopenharmony_ci .len = (unsigned short)ARRAY_SIZE(strict_filter), 62f08c3bdfSopenharmony_ci .filter = (struct sock_filter *)strict_filter 63f08c3bdfSopenharmony_ci}; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_cistatic void check_strict_mode(int); 66f08c3bdfSopenharmony_cistatic void check_filter_mode(int); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_cistatic struct tcase { 69f08c3bdfSopenharmony_ci void (*func_check)(); 70f08c3bdfSopenharmony_ci int pass_flag; 71f08c3bdfSopenharmony_ci int val; 72f08c3bdfSopenharmony_ci int exp_signal; 73f08c3bdfSopenharmony_ci char *message; 74f08c3bdfSopenharmony_ci} tcases[] = { 75f08c3bdfSopenharmony_ci {check_strict_mode, 1, 1, SIGKILL, 76f08c3bdfSopenharmony_ci "SECCOMP_MODE_STRICT doesn't permit GET_SECCOMP call"}, 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_ci {check_strict_mode, 0, 2, SIGKILL, 79f08c3bdfSopenharmony_ci "SECCOMP_MODE_STRICT doesn't permit read(2) write(2) and _exit(2)"}, 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci {check_strict_mode, 1, 3, SIGKILL, 82f08c3bdfSopenharmony_ci "SECCOMP_MODE_STRICT doesn't permit close(2)"}, 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci {check_filter_mode, 1, 1, SIGSYS, 85f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER doestn't permit GET_SECCOMP call"}, 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci {check_filter_mode, 0, 2, SIGSYS, 88f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER doesn't permit close(2)"}, 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci {check_filter_mode, 2, 3, SIGSYS, 91f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER doesn't permit exit()"}, 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci {check_filter_mode, 0, 4, SIGSYS, 94f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER doesn't permit exit()"} 95f08c3bdfSopenharmony_ci}; 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_cistatic int mode_filter_not_supported; 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_cistatic void check_filter_mode_inherit(void) 101f08c3bdfSopenharmony_ci{ 102f08c3bdfSopenharmony_ci int childpid; 103f08c3bdfSopenharmony_ci int childstatus; 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci childpid = SAFE_FORK(); 106f08c3bdfSopenharmony_ci if (childpid == 0) { 107f08c3bdfSopenharmony_ci tst_res(TPASS, "SECCOMP_MODE_FILTER permits fork(2)"); 108f08c3bdfSopenharmony_ci exit(0); 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci wait4(childpid, &childstatus, 0, NULL); 112f08c3bdfSopenharmony_ci if (WIFSIGNALED(childstatus) && WTERMSIG(childstatus) == SIGSYS) 113f08c3bdfSopenharmony_ci tst_res(TPASS, 114f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER has been inherited by child"); 115f08c3bdfSopenharmony_ci else 116f08c3bdfSopenharmony_ci tst_res(TFAIL, 117f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER isn't been inherited by child"); 118f08c3bdfSopenharmony_ci} 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_cistatic void check_strict_mode(int val) 121f08c3bdfSopenharmony_ci{ 122f08c3bdfSopenharmony_ci int fd; 123f08c3bdfSopenharmony_ci char buf[2]; 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci fd = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0666); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci TEST(prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT)); 128f08c3bdfSopenharmony_ci if (TST_RET == -1) { 129f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, 130f08c3bdfSopenharmony_ci "prctl(PR_SET_SECCOMP) sets SECCOMP_MODE_STRICT failed"); 131f08c3bdfSopenharmony_ci return; 132f08c3bdfSopenharmony_ci } 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci switch (val) { 135f08c3bdfSopenharmony_ci case 1: 136f08c3bdfSopenharmony_ci tst_res(TPASS, 137f08c3bdfSopenharmony_ci "prctl(PR_SET_SECCOMP) sets SECCOMP_MODE_STRICT succeed"); 138f08c3bdfSopenharmony_ci prctl(PR_GET_SECCOMP); 139f08c3bdfSopenharmony_ci tst_res(TFAIL, "prctl(PR_GET_SECCOMP) succeed unexpectedly"); 140f08c3bdfSopenharmony_ci break; 141f08c3bdfSopenharmony_ci case 2: 142f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fd, "a", 1); 143f08c3bdfSopenharmony_ci SAFE_READ(0, fd, buf, 1); 144f08c3bdfSopenharmony_ci tst_res(TPASS, 145f08c3bdfSopenharmony_ci "SECCOMP_MODE_STRICT permits read(2) write(2) and _exit(2)"); 146f08c3bdfSopenharmony_ci break; 147f08c3bdfSopenharmony_ci case 3: 148f08c3bdfSopenharmony_ci close(fd); 149f08c3bdfSopenharmony_ci tst_res(TFAIL, 150f08c3bdfSopenharmony_ci "SECCOMP_MODE_STRICT permits close(2) unexpectdly"); 151f08c3bdfSopenharmony_ci break; 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci tst_syscall(__NR_exit, 0); 155f08c3bdfSopenharmony_ci} 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_cistatic void check_filter_mode(int val) 158f08c3bdfSopenharmony_ci{ 159f08c3bdfSopenharmony_ci int fd; 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci if (mode_filter_not_supported == 1) { 162f08c3bdfSopenharmony_ci tst_res(TCONF, "kernel doesn't support SECCOMP_MODE_FILTER"); 163f08c3bdfSopenharmony_ci return; 164f08c3bdfSopenharmony_ci } 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci fd = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0666); 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci TEST(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &strict)); 169f08c3bdfSopenharmony_ci if (TST_RET == -1) { 170f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, 171f08c3bdfSopenharmony_ci "prctl(PR_SET_SECCOMP) sets SECCOMP_MODE_FILTER failed"); 172f08c3bdfSopenharmony_ci return; 173f08c3bdfSopenharmony_ci } 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci switch (val) { 176f08c3bdfSopenharmony_ci case 1: 177f08c3bdfSopenharmony_ci tst_res(TPASS, 178f08c3bdfSopenharmony_ci "prctl(PR_SET_SECCOMP) sets SECCOMP_MODE_FILTER succeed"); 179f08c3bdfSopenharmony_ci prctl(PR_GET_SECCOMP); 180f08c3bdfSopenharmony_ci tst_res(TFAIL, "prctl(PR_GET_SECCOMP) succeed unexpectedly"); 181f08c3bdfSopenharmony_ci break; 182f08c3bdfSopenharmony_ci case 2: 183f08c3bdfSopenharmony_ci close(fd); 184f08c3bdfSopenharmony_ci tst_res(TPASS, "SECCOMP_MODE_FILTER permits close(2)"); 185f08c3bdfSopenharmony_ci break; 186f08c3bdfSopenharmony_ci case 3: 187f08c3bdfSopenharmony_ci exit(0); 188f08c3bdfSopenharmony_ci break; 189f08c3bdfSopenharmony_ci case 4: 190f08c3bdfSopenharmony_ci check_filter_mode_inherit(); 191f08c3bdfSopenharmony_ci break; 192f08c3bdfSopenharmony_ci } 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_ci tst_syscall(__NR_exit, 0); 195f08c3bdfSopenharmony_ci} 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_cistatic void verify_prctl(unsigned int n) 198f08c3bdfSopenharmony_ci{ 199f08c3bdfSopenharmony_ci int pid; 200f08c3bdfSopenharmony_ci int status; 201f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 202f08c3bdfSopenharmony_ci 203f08c3bdfSopenharmony_ci pid = SAFE_FORK(); 204f08c3bdfSopenharmony_ci if (pid == 0) { 205f08c3bdfSopenharmony_ci tc->func_check(tc->val); 206f08c3bdfSopenharmony_ci } else { 207f08c3bdfSopenharmony_ci SAFE_WAITPID(pid, &status, 0); 208f08c3bdfSopenharmony_ci if (WIFSIGNALED(status) && WTERMSIG(status) == tc->exp_signal) { 209f08c3bdfSopenharmony_ci if (tc->pass_flag) 210f08c3bdfSopenharmony_ci tst_res(TPASS, "%s", tc->message); 211f08c3bdfSopenharmony_ci else 212f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s", tc->message); 213f08c3bdfSopenharmony_ci return; 214f08c3bdfSopenharmony_ci } 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci if (tc->pass_flag == 2 && mode_filter_not_supported == 0) 217f08c3bdfSopenharmony_ci tst_res(TFAIL, 218f08c3bdfSopenharmony_ci "SECCOMP_MODE_FILTER permits exit() unexpectedly"); 219f08c3bdfSopenharmony_ci } 220f08c3bdfSopenharmony_ci} 221f08c3bdfSopenharmony_ci 222f08c3bdfSopenharmony_cistatic void setup(void) 223f08c3bdfSopenharmony_ci{ 224f08c3bdfSopenharmony_ci TEST(prctl(PR_GET_SECCOMP)); 225f08c3bdfSopenharmony_ci if (TST_RET == 0) { 226f08c3bdfSopenharmony_ci tst_res(TINFO, "kernel supports PR_GET/SET_SECCOMP"); 227f08c3bdfSopenharmony_ci 228f08c3bdfSopenharmony_ci TEST(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL)); 229f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR == EINVAL) { 230f08c3bdfSopenharmony_ci mode_filter_not_supported = 1; 231f08c3bdfSopenharmony_ci return; 232f08c3bdfSopenharmony_ci } 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_ci tst_res(TINFO, "kernel supports SECCOMP_MODE_FILTER"); 235f08c3bdfSopenharmony_ci return; 236f08c3bdfSopenharmony_ci } 237f08c3bdfSopenharmony_ci 238f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 239f08c3bdfSopenharmony_ci tst_brk(TCONF, "kernel doesn't support PR_GET/SET_SECCOMP"); 240f08c3bdfSopenharmony_ci 241f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 242f08c3bdfSopenharmony_ci "current environment doesn't permit PR_GET/SET_SECCOMP"); 243f08c3bdfSopenharmony_ci} 244f08c3bdfSopenharmony_ci 245f08c3bdfSopenharmony_cistatic struct tst_test test = { 246f08c3bdfSopenharmony_ci .setup = setup, 247f08c3bdfSopenharmony_ci .test = verify_prctl, 248f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 249f08c3bdfSopenharmony_ci .forks_child = 1, 250f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 251f08c3bdfSopenharmony_ci .needs_root = 1, 252f08c3bdfSopenharmony_ci}; 253