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_NO_NEW_PRIVS and PR_SET_NO_NEW_PRIVS of prctl(2).
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * - Return the value of the no_new_privs bit for the calling thread.
13f08c3bdfSopenharmony_ci *   A value of 0 indicates the regular execve(2) behavior.  A value of
14f08c3bdfSopenharmony_ci *   1 indicates execve(2) will operate in the privilege-restricting mode.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * - With no_new_privs set to 1, diables privilege granting operations
17f08c3bdfSopenharmony_ci *   at execve-time. For example, a process will not be able to execute a
18f08c3bdfSopenharmony_ci *   setuid binary to change their uid or gid if this bit is set. The same
19f08c3bdfSopenharmony_ci *   is true for file capabilities.
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci * - The setting of this bit is inherited by children created by fork(2),
22f08c3bdfSopenharmony_ci *   and preserved across execve(2). We also check NoNewPrivs field in
23f08c3bdfSopenharmony_ci *   /proc/self/status if it supports.
24f08c3bdfSopenharmony_ci */
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#include "prctl06.h"
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic uid_t nobody_uid;
29f08c3bdfSopenharmony_cistatic gid_t nobody_gid;
30f08c3bdfSopenharmony_cistatic int proc_flag = 1;
31f08c3bdfSopenharmony_cistatic char *proc_sup = "Yes";
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic void do_prctl(void)
34f08c3bdfSopenharmony_ci{
35f08c3bdfSopenharmony_ci	char ipc_env_var[1024];
36f08c3bdfSopenharmony_ci	char *const argv[] = {BIN_PATH, "After execve, parent process", proc_sup, NULL};
37f08c3bdfSopenharmony_ci	char *const childargv[] = {BIN_PATH, "After execve, child process", proc_sup, NULL};
38f08c3bdfSopenharmony_ci	char *const envp[] = {ipc_env_var, NULL };
39f08c3bdfSopenharmony_ci	int childpid;
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci	check_no_new_privs(0, "parent", proc_flag);
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
44f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
45f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
46f08c3bdfSopenharmony_ci		return;
47f08c3bdfSopenharmony_ci	}
48f08c3bdfSopenharmony_ci	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_ci	SAFE_SETGID(nobody_gid);
51f08c3bdfSopenharmony_ci	SAFE_SETUID(nobody_uid);
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	childpid = SAFE_FORK();
56f08c3bdfSopenharmony_ci	if (childpid == 0) {
57f08c3bdfSopenharmony_ci		check_no_new_privs(1, "After fork, child process", proc_flag);
58f08c3bdfSopenharmony_ci		execve(BIN_PATH, childargv, envp);
59f08c3bdfSopenharmony_ci		tst_brk(TFAIL | TERRNO,
60f08c3bdfSopenharmony_ci			"child process failed to execute prctl_execve");
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_ci	} else {
63f08c3bdfSopenharmony_ci		tst_reap_children();
64f08c3bdfSopenharmony_ci		check_no_new_privs(1, "parent process", proc_flag);
65f08c3bdfSopenharmony_ci		execve(BIN_PATH, argv, envp);
66f08c3bdfSopenharmony_ci		tst_brk(TFAIL | TERRNO,
67f08c3bdfSopenharmony_ci			"parent process failed to execute prctl_execve");
68f08c3bdfSopenharmony_ci	}
69f08c3bdfSopenharmony_ci}
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_cistatic void verify_prctl(void)
72f08c3bdfSopenharmony_ci{
73f08c3bdfSopenharmony_ci	int pid;
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
76f08c3bdfSopenharmony_ci	if (pid == 0) {
77f08c3bdfSopenharmony_ci		do_prctl();
78f08c3bdfSopenharmony_ci		exit(0);
79f08c3bdfSopenharmony_ci	}
80f08c3bdfSopenharmony_ci}
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_cistatic void setup(void)
83f08c3bdfSopenharmony_ci{
84f08c3bdfSopenharmony_ci	struct passwd *pw;
85f08c3bdfSopenharmony_ci	int field;
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci	pw = SAFE_GETPWNAM("nobody");
88f08c3bdfSopenharmony_ci	nobody_uid = pw->pw_uid;
89f08c3bdfSopenharmony_ci	nobody_gid = pw->pw_gid;
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	SAFE_CP(TESTBIN, TEST_REL_BIN_DIR);
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	SAFE_CHOWN(BIN_PATH, 0, 0);
94f08c3bdfSopenharmony_ci	SAFE_CHMOD(BIN_PATH, SUID_MODE);
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	if (FILE_LINES_SCANF(PROC_STATUS, "NoNewPrivs:%d", &field)) {
97f08c3bdfSopenharmony_ci		tst_res(TCONF, "%s doesn't support NoNewPrivs field", PROC_STATUS);
98f08c3bdfSopenharmony_ci		proc_flag = 0;
99f08c3bdfSopenharmony_ci		proc_sup = "No";
100f08c3bdfSopenharmony_ci	}
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
103f08c3bdfSopenharmony_ci	if (TST_RET == 0) {
104f08c3bdfSopenharmony_ci		tst_res(TINFO, "kernel supports PR_GET/SET_NO_NEW_PRIVS");
105f08c3bdfSopenharmony_ci		return;
106f08c3bdfSopenharmony_ci	}
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_ci	if (TST_ERR == EINVAL)
109f08c3bdfSopenharmony_ci		tst_brk(TCONF,
110f08c3bdfSopenharmony_ci			"kernel doesn't support PR_GET/SET_NO_NEW_PRIVS");
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	tst_brk(TBROK | TTERRNO,
113f08c3bdfSopenharmony_ci		"current environment doesn't permit PR_GET/SET_NO_NEW_PRIVS");
114f08c3bdfSopenharmony_ci}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_cistatic struct tst_test test = {
117f08c3bdfSopenharmony_ci	.resource_files = (const char *const []) {
118f08c3bdfSopenharmony_ci		TESTBIN,
119f08c3bdfSopenharmony_ci		NULL
120f08c3bdfSopenharmony_ci	},
121f08c3bdfSopenharmony_ci	.setup = setup,
122f08c3bdfSopenharmony_ci	.test_all = verify_prctl,
123f08c3bdfSopenharmony_ci	.forks_child = 1,
124f08c3bdfSopenharmony_ci	.needs_root = 1,
125f08c3bdfSopenharmony_ci	.mount_device = 1,
126f08c3bdfSopenharmony_ci	.mntpoint = MNTPOINT,
127f08c3bdfSopenharmony_ci	.child_needs_reinit = 1,
128f08c3bdfSopenharmony_ci};
129