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