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