1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/*\ 7f08c3bdfSopenharmony_ci * [Description] 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * - EINVAL when an invalid value is given for option 10f08c3bdfSopenharmony_ci * - EINVAL when option is PR_SET_PDEATHSIG & arg2 is not zero or a valid 11f08c3bdfSopenharmony_ci * signal number 12f08c3bdfSopenharmony_ci * - EINVAL when option is PR_SET_DUMPABLE & arg2 is neither 13f08c3bdfSopenharmony_ci * SUID_DUMP_DISABLE nor SUID_DUMP_USER 14f08c3bdfSopenharmony_ci * - EFAULT when arg2 is an invalid address 15f08c3bdfSopenharmony_ci * - EFAULT when option is PR_SET_SECCOMP & arg2 is SECCOMP_MODE_FILTER & 16f08c3bdfSopenharmony_ci * arg3 is an invalid address 17f08c3bdfSopenharmony_ci * - EACCES when option is PR_SET_SECCOMP & arg2 is SECCOMP_MODE_FILTER & 18f08c3bdfSopenharmony_ci * the process does not have the CAP_SYS_ADMIN capability 19f08c3bdfSopenharmony_ci * - EINVAL when option is PR_SET_TIMING & arg2 is not PR_TIMING_STATISTICAL 20f08c3bdfSopenharmony_ci * - EINVAL when option is PR_SET_NO_NEW_PRIVS & arg2 is not equal to 1 & 21f08c3bdfSopenharmony_ci * arg3 is zero 22f08c3bdfSopenharmony_ci * - EINVAL when option is PR_SET_NO_NEW_PRIVS & arg2 is equal to 1 & arg3 23f08c3bdfSopenharmony_ci * is nonzero 24f08c3bdfSopenharmony_ci * - EINVAL when options is PR_GET_NO_NEW_PRIVS & arg2, arg3, arg4, or arg5 25f08c3bdfSopenharmony_ci * is nonzero 26f08c3bdfSopenharmony_ci * - EINVAL when options is PR_SET_THP_DISABLE & arg3, arg4, arg5 is non-zero. 27f08c3bdfSopenharmony_ci * - EINVAL when options is PR_GET_THP_DISABLE & arg2, arg3, arg4, or arg5 is 28f08c3bdfSopenharmony_ci * nonzero 29f08c3bdfSopenharmony_ci * - EINVAL when options is PR_CAP_AMBIENT & arg2 has an invalid value 30f08c3bdfSopenharmony_ci * - EINVAL when options is PR_CAP_AMBIENT & an unused argument such as arg4, 31f08c3bdfSopenharmony_ci * arg5, or, in the case of PR_CAP_AMBIENT_CLEAR_ALL, arg3 is nonzero 32f08c3bdfSopenharmony_ci * - EINVAL when options is PR_CAP_AMBIENT & arg2 is PR_CAP_AMBIENT_LOWER, 33f08c3bdfSopenharmony_ci * PR_CAP_AMBIENT_RAISE, or PR_CAP_AMBIENT_IS_SET and arg3 does not specify 34f08c3bdfSopenharmony_ci * a valid capability 35f08c3bdfSopenharmony_ci * - EINVAL when option is PR_GET_SPECULATION_CTRL and unused arguments is 36f08c3bdfSopenharmony_ci * nonzero 37f08c3bdfSopenharmony_ci * - EPERM when option is PR_SET_SECUREBITS and the caller does not have the 38f08c3bdfSopenharmony_ci * CAP_SETPCAP capability 39f08c3bdfSopenharmony_ci * - EPERM when option is PR_CAPBSET_DROP and the caller does not have the 40f08c3bdfSopenharmony_ci * CAP_SETPCAP capability 41f08c3bdfSopenharmony_ci */ 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#include <errno.h> 44f08c3bdfSopenharmony_ci#include <signal.h> 45f08c3bdfSopenharmony_ci#include <sys/prctl.h> 46f08c3bdfSopenharmony_ci#include <linux/filter.h> 47f08c3bdfSopenharmony_ci#include <linux/capability.h> 48f08c3bdfSopenharmony_ci#include <unistd.h> 49f08c3bdfSopenharmony_ci#include <stdlib.h> 50f08c3bdfSopenharmony_ci#include <stddef.h> 51f08c3bdfSopenharmony_ci#include <limits.h> 52f08c3bdfSopenharmony_ci#include "config.h" 53f08c3bdfSopenharmony_ci#include "lapi/prctl.h" 54f08c3bdfSopenharmony_ci#include "lapi/seccomp.h" 55f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 56f08c3bdfSopenharmony_ci#include "tst_test.h" 57f08c3bdfSopenharmony_ci#include "tst_capability.h" 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci#define OPTION_INVALID 999 60f08c3bdfSopenharmony_ci#define unsup_string "prctl() doesn't support this option, skip it" 61f08c3bdfSopenharmony_cistatic const struct sock_filter strict_filter[] = { 62f08c3bdfSopenharmony_ci BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) 63f08c3bdfSopenharmony_ci}; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_cistatic const struct sock_fprog strict = { 66f08c3bdfSopenharmony_ci .len = (unsigned short)ARRAY_SIZE(strict_filter), 67f08c3bdfSopenharmony_ci .filter = (struct sock_filter *)strict_filter 68f08c3bdfSopenharmony_ci}; 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_cistatic unsigned long strict_addr = (unsigned long)&strict; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_cistatic unsigned long bad_addr; 73f08c3bdfSopenharmony_cistatic unsigned long num_0; 74f08c3bdfSopenharmony_cistatic unsigned long num_1 = 1; 75f08c3bdfSopenharmony_cistatic unsigned long num_2 = 2; 76f08c3bdfSopenharmony_cistatic unsigned long num_PR_CAP_AMBIENT_CLEAR_ALL = PR_CAP_AMBIENT_CLEAR_ALL; 77f08c3bdfSopenharmony_cistatic unsigned long num_PR_CAP_AMBIENT_IS_SET = PR_CAP_AMBIENT_IS_SET; 78f08c3bdfSopenharmony_cistatic unsigned long num_invalid = ULONG_MAX; 79f08c3bdfSopenharmony_cistatic int seccomp_nsup; 80f08c3bdfSopenharmony_cistatic int nonewprivs_nsup; 81f08c3bdfSopenharmony_cistatic int thpdisable_nsup; 82f08c3bdfSopenharmony_cistatic int capambient_nsup; 83f08c3bdfSopenharmony_cistatic int speculationctrl_nsup; 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_cistatic struct tcase { 86f08c3bdfSopenharmony_ci int option; 87f08c3bdfSopenharmony_ci unsigned long *arg2; 88f08c3bdfSopenharmony_ci unsigned long *arg3; 89f08c3bdfSopenharmony_ci int exp_errno; 90f08c3bdfSopenharmony_ci char *tname; 91f08c3bdfSopenharmony_ci} tcases[] = { 92f08c3bdfSopenharmony_ci {OPTION_INVALID, &num_1, &num_0, EINVAL, "invalid option"}, 93f08c3bdfSopenharmony_ci {PR_SET_PDEATHSIG, &num_invalid, &num_0, EINVAL, "PR_SET_PDEATHSIG"}, 94f08c3bdfSopenharmony_ci {PR_SET_DUMPABLE, &num_2, &num_0, EINVAL, "PR_SET_DUMPABLE"}, 95f08c3bdfSopenharmony_ci {PR_SET_NAME, &bad_addr, &num_0, EFAULT, "PR_SET_NAME"}, 96f08c3bdfSopenharmony_ci {PR_SET_SECCOMP, &num_2, &bad_addr, EFAULT, "PR_SET_SECCOMP"}, 97f08c3bdfSopenharmony_ci {PR_SET_SECCOMP, &num_2, &strict_addr, EACCES, "PR_SET_SECCOMP"}, 98f08c3bdfSopenharmony_ci {PR_SET_TIMING, &num_1, &num_0, EINVAL, "PR_SET_TIMING"}, 99f08c3bdfSopenharmony_ci {PR_SET_NO_NEW_PRIVS, &num_0, &num_0, EINVAL, "PR_SET_NO_NEW_PRIVS"}, 100f08c3bdfSopenharmony_ci {PR_SET_NO_NEW_PRIVS, &num_1, &num_1, EINVAL, "PR_SET_NO_NEW_PRIVS"}, 101f08c3bdfSopenharmony_ci {PR_GET_NO_NEW_PRIVS, &num_1, &num_0, EINVAL, "PR_GET_NO_NEW_PRIVS"}, 102f08c3bdfSopenharmony_ci {PR_SET_THP_DISABLE, &num_0, &num_1, EINVAL, "PR_SET_THP_DISABLE"}, 103f08c3bdfSopenharmony_ci {PR_GET_THP_DISABLE, &num_1, &num_1, EINVAL, "PR_GET_THP_DISABLE"}, 104f08c3bdfSopenharmony_ci {PR_CAP_AMBIENT, &num_invalid, &num_0, EINVAL, "PR_CAP_AMBIENT"}, 105f08c3bdfSopenharmony_ci {PR_CAP_AMBIENT, &num_PR_CAP_AMBIENT_CLEAR_ALL, &num_1, EINVAL, "PR_CAP_AMBIENT"}, 106f08c3bdfSopenharmony_ci {PR_CAP_AMBIENT, &num_PR_CAP_AMBIENT_IS_SET, &num_invalid, EINVAL, "PR_CAP_AMBIENT"}, 107f08c3bdfSopenharmony_ci {PR_GET_SPECULATION_CTRL, &num_0, &num_invalid, EINVAL, "PR_GET_SPECULATION_CTRL"}, 108f08c3bdfSopenharmony_ci {PR_SET_SECUREBITS, &num_0, &num_0, EPERM, "PR_SET_SECUREBITS"}, 109f08c3bdfSopenharmony_ci {PR_CAPBSET_DROP, &num_1, &num_0, EPERM, "PR_CAPBSET_DROP"}, 110f08c3bdfSopenharmony_ci}; 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_cistatic void verify_prctl(unsigned int n) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", n, tc->tname); 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_ci switch (tc->option) { 119f08c3bdfSopenharmony_ci case PR_SET_SECCOMP: 120f08c3bdfSopenharmony_ci if (seccomp_nsup) { 121f08c3bdfSopenharmony_ci tst_res(TCONF, "%s", unsup_string); 122f08c3bdfSopenharmony_ci return; 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci break; 125f08c3bdfSopenharmony_ci case PR_GET_NO_NEW_PRIVS: 126f08c3bdfSopenharmony_ci case PR_SET_NO_NEW_PRIVS: 127f08c3bdfSopenharmony_ci if (nonewprivs_nsup) { 128f08c3bdfSopenharmony_ci tst_res(TCONF, "%s", unsup_string); 129f08c3bdfSopenharmony_ci return; 130f08c3bdfSopenharmony_ci } 131f08c3bdfSopenharmony_ci break; 132f08c3bdfSopenharmony_ci case PR_SET_THP_DISABLE: 133f08c3bdfSopenharmony_ci case PR_GET_THP_DISABLE: 134f08c3bdfSopenharmony_ci if (thpdisable_nsup) { 135f08c3bdfSopenharmony_ci tst_res(TCONF, "%s", unsup_string); 136f08c3bdfSopenharmony_ci return; 137f08c3bdfSopenharmony_ci } 138f08c3bdfSopenharmony_ci break; 139f08c3bdfSopenharmony_ci case PR_CAP_AMBIENT: 140f08c3bdfSopenharmony_ci if (capambient_nsup) { 141f08c3bdfSopenharmony_ci tst_res(TCONF, "%s", unsup_string); 142f08c3bdfSopenharmony_ci return; 143f08c3bdfSopenharmony_ci } 144f08c3bdfSopenharmony_ci break; 145f08c3bdfSopenharmony_ci case PR_GET_SPECULATION_CTRL: 146f08c3bdfSopenharmony_ci if (speculationctrl_nsup) { 147f08c3bdfSopenharmony_ci tst_res(TCONF, "%s", unsup_string); 148f08c3bdfSopenharmony_ci return; 149f08c3bdfSopenharmony_ci } 150f08c3bdfSopenharmony_ci break; 151f08c3bdfSopenharmony_ci default: 152f08c3bdfSopenharmony_ci break; 153f08c3bdfSopenharmony_ci } 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci TEST(prctl(tc->option, *tc->arg2, *tc->arg3, 0, 0)); 156f08c3bdfSopenharmony_ci if (TST_RET == 0) { 157f08c3bdfSopenharmony_ci tst_res(TFAIL, "prctl() succeeded unexpectedly"); 158f08c3bdfSopenharmony_ci return; 159f08c3bdfSopenharmony_ci } 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci if (tc->exp_errno == TST_ERR) { 162f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "prctl() failed as expected"); 163f08c3bdfSopenharmony_ci } else { 164f08c3bdfSopenharmony_ci if (tc->option == PR_SET_SECCOMP && TST_ERR == EINVAL) 165f08c3bdfSopenharmony_ci tst_res(TCONF, "current system was not built with CONFIG_SECCOMP_FILTER."); 166f08c3bdfSopenharmony_ci else 167f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", 168f08c3bdfSopenharmony_ci tst_strerrno(tc->exp_errno)); 169f08c3bdfSopenharmony_ci } 170f08c3bdfSopenharmony_ci} 171f08c3bdfSopenharmony_ci 172f08c3bdfSopenharmony_cistatic void setup(void) 173f08c3bdfSopenharmony_ci{ 174f08c3bdfSopenharmony_ci bad_addr = (unsigned long)tst_get_bad_addr(NULL); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci TEST(prctl(PR_GET_SECCOMP)); 177f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 178f08c3bdfSopenharmony_ci seccomp_nsup = 1; 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)); 181f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 182f08c3bdfSopenharmony_ci nonewprivs_nsup = 1; 183f08c3bdfSopenharmony_ci 184f08c3bdfSopenharmony_ci TEST(prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0)); 185f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 186f08c3bdfSopenharmony_ci thpdisable_nsup = 1; 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_ci TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0)); 189f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 190f08c3bdfSopenharmony_ci capambient_nsup = 1; 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci TEST(prctl(PR_GET_SPECULATION_CTRL, 0, 0, 0, 0)); 193f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 194f08c3bdfSopenharmony_ci speculationctrl_nsup = 1; 195f08c3bdfSopenharmony_ci} 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_cistatic struct tst_test test = { 198f08c3bdfSopenharmony_ci .setup = setup, 199f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 200f08c3bdfSopenharmony_ci .test = verify_prctl, 201f08c3bdfSopenharmony_ci .caps = (struct tst_cap []) { 202f08c3bdfSopenharmony_ci TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), 203f08c3bdfSopenharmony_ci TST_CAP(TST_CAP_DROP, CAP_SETPCAP), 204f08c3bdfSopenharmony_ci {} 205f08c3bdfSopenharmony_ci }, 206f08c3bdfSopenharmony_ci}; 207