Skip to contentSkip to conversation

syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

PATCH Superseded Yang Xu 2 participants 15 messages May 9, 2019 – Jul 16, 2019

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Yang Xu

author
#0 lore raw

PATCH 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

---
 include/lapi/prctl.h                          |   5 +
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/prctl/.gitignore    |   1 +
 testcases/kernel/syscalls/prctl/Makefile      |   2 +
 testcases/kernel/syscalls/prctl/prctl06.c     | 117 ++++++++++++++++++
 .../kernel/syscalls/prctl/prctl06_execve.c    |  46 +++++++
 6 files changed, 172 insertions(+)
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06.c
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06_execve.c
include/lapi/prctl.h +5 -0
index 91da9c2d6..663ce19e9 100644
@@ -24,4 +24,9 @@
 # define PR_SET_SECCOMP  22
 #endif
 
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+
 #endif /* LAPI_PRCTL_H__ */
runtest/syscalls +1 -0
index 950615bef..a43bf5e4d 100644
@@ -865,6 +865,7 @@ prctl02 prctl02
 prctl03 prctl03
 prctl04 prctl04
 prctl05 prctl05
+prctl06 prctl06
 
 pread01 pread01
 pread01_64 pread01_64
testcases/kernel/syscalls/prctl/.gitignore +1 -0
index 9ecaf9854..f52f6f665 100644
@@ -3,3 +3,4 @@
 /prctl03
 /prctl04
 /prctl05
+/prctl06
testcases/kernel/syscalls/prctl/Makefile +2 -0
index bd617d806..99a9d42e7 100644
@@ -20,4 +20,6 @@ top_srcdir		?= ../../../..
 
 include $(top_srcdir)/include/mk/testcases.mk
 
+LDLIBS			+= $(CAP_LIBS)
+
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
testcases/kernel/syscalls/prctl/prctl06.c new file +117 -0

117 lines not on this page · raw message

testcases/kernel/syscalls/prctl/prctl06_execve.c new file +46 -0

46 lines not on this page · raw message

Signature · 1 line
2.18.1
author
#1 lore raw

PATCH 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Hi
Ping.:-)

Quoted 233 lines
---
 include/lapi/prctl.h                          |   5 +
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/prctl/.gitignore    |   1 +
 testcases/kernel/syscalls/prctl/Makefile      |   2 +
 testcases/kernel/syscalls/prctl/prctl06.c     | 117 ++++++++++++++++++
 .../kernel/syscalls/prctl/prctl06_execve.c    |  46 +++++++
 6 files changed, 172 insertions(+)
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06.c
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06_execve.c
include/lapi/prctl.h +5 -0
index 91da9c2d6..663ce19e9 100644
@@ -24,4 +24,9 @@
 # define PR_SET_SECCOMP  22
 #endif
 
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+
 #endif /* LAPI_PRCTL_H__ */
runtest/syscalls +1 -0
index 950615bef..a43bf5e4d 100644
@@ -865,6 +865,7 @@ prctl02 prctl02
 prctl03 prctl03
 prctl04 prctl04
 prctl05 prctl05
+prctl06 prctl06
 
 pread01 pread01
 pread01_64 pread01_64
testcases/kernel/syscalls/prctl/.gitignore +1 -0
index 9ecaf9854..f52f6f665 100644
@@ -3,3 +3,4 @@
 /prctl03
 /prctl04
 /prctl05
+/prctl06
testcases/kernel/syscalls/prctl/Makefile +2 -0
index bd617d806..99a9d42e7 100644
@@ -20,4 +20,6 @@ top_srcdir		?= ../../../..
 
 include $(top_srcdir)/include/mk/testcases.mk
 
+LDLIBS			+= $(CAP_LIBS)
+
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
testcases/kernel/syscalls/prctl/prctl06.c new file +117 -0
new file mode 100644
index 000000000..ba5c2bcfb
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <[email protected]>
+ *
+ * Test PR_GET_NO_NEW_PRIVS and PR_SET_NO_NEW_PRIVS of prctl(2).
+ *
+ * 1)Return (as the function result) the value of the no_new_privs bit
+ *   for the calling thread. A value of 0 indicates the regular execve(2)
+ *   behavior.  A value of 1 indicates execve(2) will operate in the
+ *   privilege-restricting mode.
+ * 2)With no_new_privs set to 1, execve(2) promises not to grant privileges
+ *   to do anything that could not have been done without the execve(2)
+ *   call(for example, rendering the set-user-ID and set-group-ID mode bits)
+ * 3)The setting of this bit is inherited by children created by fork(2) and
+ *   clone(2), and preserved across execve(2).
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/capability.h>
+#include <lapi/prctl.h>
+#include "tst_test.h"
+
+#define IPC_ENV_VAR "LTP_IPC_PATH"
+
+static void check_no_new_privs(int val)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"prctl(PR_GET_NO_NEW_PRIVS) got %d "
+			"when no_new_privs was %d", val, val);
+	else
+		tst_res(TFAIL | TTERRNO,
+			"prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			val, TST_RET);
+	return;
+}
+
+static void do_prctl(void)
+{
+	char path[4096];
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", NULL};
+	char *const envp[] = {"LTP_TEST_ENV_VAR=test", ipc_env_var, NULL };
+	cap_t caps = cap_init();
+	cap_value_t capList = CAP_SETGID;
+	unsigned int num_caps = 1;
+	int childpid;
+
+	cap_set_flag(caps, CAP_EFFECTIVE, num_caps, &capList, CAP_SET);
+	cap_set_flag(caps, CAP_INHERITABLE, num_caps, &capList, CAP_SET);
+	cap_set_flag(caps, CAP_PERMITTED, num_caps, &capList, CAP_SET);
+
+	if (cap_set_proc(caps))
+		tst_brk(TFAIL | TERRNO,
+			"cap_set_flag(CAP_SETGID) failed");
+	tst_res(TINFO, "cap_set_flag(CAP_SETGID) succeeded");
+
+	check_no_new_privs(0);
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
+
+	check_no_new_privs(1);
+
+	if (tst_get_path("prctl06_execve", path, sizeof(path)))
+		tst_brk(TCONF, "Couldn't find prctl_execve in $PATH");
+
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1);
+		execve(path, childargv, envp);
+		tst_brk(TFAIL | TERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		execve(path, argv, envp);
+		tst_brk(TFAIL | TERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+	cap_free(caps);
+	return;
+}
+
+static void verify_prctl(void)
+{
+	int pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+	tst_reap_children();
+	return;
+}
+
+static struct tst_test test = {
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +46 -0
new file mode 100644
index 000000000..84c28551c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{
+	struct passwd *pw;
+	uid_t nobody_uid;
+	gid_t nobody_gid;
+
+	tst_reinit();
+	if (argc != 2)
+		tst_brk(TFAIL, "argc is %d, expected 2", argc);
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;
+	/*positive check*/
+	TEST(setgid(nobody_gid));
+	if (TST_RET == -1)
+		tst_res(TFAIL | TTERRNO,
+			"%s setgid(%d) isn't permmit", argv[1], nobody_gid);
+	else
+		tst_res(TPASS, "%s setgid(%d) succeed expectedly",
+			argv[1], nobody_gid);
+	/*negative check*/
+	TEST(setuid(nobody_uid));
+	if (TST_RET == -1)
+		tst_res(TPASS | TTERRNO,
+			"%s setuid(%d) isn't permmit", argv[1], nobody_uid);
+	else
+		tst_res(TFAIL, " %s setuid(%d) succeed unexpectedly",
+			argv[1], nobody_gid);
+	return 0;
+}
#2 lore raw

PATCH 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

In reply to Yang Xu

Hi!

Quoted 4 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +4 -0
+#define IPC_ENV_VAR "LTP_IPC_PATH"
+
+static void check_no_new_privs(int val)
+{

testcases/kernel/syscalls/prctl/prctl06.c line 43

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"prctl(PR_GET_NO_NEW_PRIVS) got %d "
+			"when no_new_privs was %d", val, val);
+	else
+		tst_res(TFAIL | TTERRNO,
+			"prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			val, TST_RET);
+	return;

This return is useless.

Quoted 11 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +11 -0
+}
+
+static void do_prctl(void)
+{
+	char path[4096];
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", NULL};
+	char *const envp[] = {"LTP_TEST_ENV_VAR=test", ipc_env_var, NULL };
+	cap_t caps = cap_init();
+	cap_value_t capList = CAP_SETGID;

testcases/kernel/syscalls/prctl/prctl06.c line 64

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+	unsigned int num_caps = 1;
+	int childpid;
+
+	cap_set_flag(caps, CAP_EFFECTIVE, num_caps, &capList, CAP_SET);
+	cap_set_flag(caps, CAP_INHERITABLE, num_caps, &capList, CAP_SET);
+	cap_set_flag(caps, CAP_PERMITTED, num_caps, &capList, CAP_SET);
+
+	if (cap_set_proc(caps))
+		tst_brk(TFAIL | TERRNO,
+			"cap_set_flag(CAP_SETGID) failed");

You cannot use tst_brk with TFAIL, the best you can do here is to use tst_ret(TFAIL ... ) then return; as you do below.

Quoted 5 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +5 -0
+	tst_res(TINFO, "cap_set_flag(CAP_SETGID) succeeded");
+
+	check_no_new_privs(0);
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));

testcases/kernel/syscalls/prctl/prctl06.c line 79

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
+
+	check_no_new_privs(1);
+
+	if (tst_get_path("prctl06_execve", path, sizeof(path)))
+		tst_brk(TCONF, "Couldn't find prctl_execve in $PATH");

If the path to the binary is in $PATH you don't have to execute the binary by an absolute path, passing it's name to execve() should suffice.

testcases/kernel/syscalls/prctl/prctl06.c line 84

Quoted 4 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +4 -0
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1);

Maybe we can pass a "child" string here and "parent" string in the cases above so that we can print if the check was done in child/parent in the tst_res() inside of this function.

Quoted 75 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +33 -0
+		execve(path, childargv, envp);
+		tst_brk(TFAIL | TERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		execve(path, argv, envp);
+		tst_brk(TFAIL | TERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+	cap_free(caps);
+	return;
+}
+
+static void verify_prctl(void)
+{
+	int pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+	tst_reap_children();
+	return;
+}
+
+static struct tst_test test = {
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +36 -0
new file mode 100644
index 000000000..84c28551c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{
+	struct passwd *pw;
+	uid_t nobody_uid;
+	gid_t nobody_gid;
+
+	tst_reinit();
+	if (argc != 2)
+		tst_brk(TFAIL, "argc is %d, expected 2", argc);
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;
+	/*positive check*/
+	TEST(setgid(nobody_gid));
+	if (TST_RET == -1)
+		tst_res(TFAIL | TTERRNO,
+			"%s setgid(%d) isn't permmit", argv[1], nobody_gid);
+	else
+		tst_res(TPASS, "%s setgid(%d) succeed expectedly",
+			argv[1], nobody_gid);

testcases/kernel/syscalls/prctl/prctl06_execve.c line 46

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+	/*negative check*/
+	TEST(setuid(nobody_uid));
+	if (TST_RET == -1)
+		tst_res(TPASS | TTERRNO,
+			"%s setuid(%d) isn't permmit", argv[1], nobody_uid);
+	else
+		tst_res(TFAIL, " %s setuid(%d) succeed unexpectedly",
+			argv[1], nobody_gid);
+	return 0;
+}

I do not think that this is actually testing the prctl in question. Here we actually check that capabilities were inherited over fork() + exec().

As far as I understand the PR_SET_NO_NEW_PRIVS it has been designed expecially to avoid misuse of capabilities associated with a particular file.

So the check would have to do:

1. copy the prctl06_execve binary to a $PWD
2. chmod it with S_ISUID, S_ISGID
3. the prct06_execve would be executed under user/group nobody
4. the prct06_execve itself would check if it gained root priviledges

And we can do the same for capablities as well.

I guess that we would have to format a device and mount it with support for capabilities for the test, since as far as I can tell you cannot usually do neither of set-usr-id or add capabilites to files in /tmp/.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#3 lore raw

PATCH 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Hi Cyril
Sorry for the late reply.

Quoted 16 lines

Hi!

Quoted 4 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +4 -0
+#define IPC_ENV_VAR "LTP_IPC_PATH"
+
+static void check_no_new_privs(int val)
+{

testcases/kernel/syscalls/prctl/prctl06.c line 43

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"prctl(PR_GET_NO_NEW_PRIVS) got %d "
+			"when no_new_privs was %d", val, val);
+	else
+		tst_res(TFAIL | TTERRNO,
+			"prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			val, TST_RET);
+	return;

This return is useless.

OK. I will remove it and add check for /proc/[pid]/status for NoNewPrivs.

Quoted 15 lines
Quoted 15 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +15 -0
+}
+
+static void do_prctl(void)
+{
+	char path[4096];
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", NULL};
+	char *const envp[] = {"LTP_TEST_ENV_VAR=test", ipc_env_var, NULL };
+	cap_t caps = cap_init();
+	cap_value_t capList = CAP_SETGID;
+	unsigned int num_caps = 1;
+	int childpid;
+
+	cap_set_flag(caps, CAP_EFFECTIVE, num_caps,&capList, CAP_SET);
Quoted 9 lines

testcases/kernel/syscalls/prctl/prctl06.c line 64

Quoted 6 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +6 -0
+	cap_set_flag(caps, CAP_INHERITABLE, num_caps,&capList, CAP_SET);
+	cap_set_flag(caps, CAP_PERMITTED, num_caps,&capList, CAP_SET);
+
+	if (cap_set_proc(caps))
+		tst_brk(TFAIL | TERRNO,
+			"cap_set_flag(CAP_SETGID) failed");

You cannot use tst_brk with TFAIL, the best you can do here is to use tst_ret(TFAIL ... ) then return; as you do below.

I got it.

Quoted 10 lines
Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+	tst_res(TINFO, "cap_set_flag(CAP_SETGID) succeeded");
+
+	check_no_new_privs(0);
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
Quoted 9 lines

testcases/kernel/syscalls/prctl/prctl06.c line 79

Quoted 5 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +5 -0
+
+	check_no_new_privs(1);
+
+	if (tst_get_path("prctl06_execve", path, sizeof(path)))
+		tst_brk(TCONF, "Couldn't find prctl_execve in $PATH");

If the path to the binary is in $PATH you don't have to execute the binary by an absolute path, passing it's name to execve() should suffice.

It sounds reasonable. I will pass binary_name directly.

Quoted 9 lines

testcases/kernel/syscalls/prctl/prctl06.c line 84

Quoted 4 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +4 -0
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1);

Maybe we can pass a "child" string here and "parent" string in the cases above so that we can print if the check was done in child/parent in the tst_res() inside of this function.

Ok. Pass a "child" or "parent" string can make it more clear for user.

Quoted 92 lines
Quoted 75 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +33 -0
+		execve(path, childargv, envp);
+		tst_brk(TFAIL | TERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		execve(path, argv, envp);
+		tst_brk(TFAIL | TERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+	cap_free(caps);
+	return;
+}
+
+static void verify_prctl(void)
+{
+	int pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+	tst_reap_children();
+	return;
+}
+
+static struct tst_test test = {
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +36 -0
new file mode 100644
index 000000000..84c28551c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu<[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include<stdlib.h>
+#include<sys/types.h>
+#include<unistd.h>
+#include<errno.h>
+#include<pwd.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{
+	struct passwd *pw;
+	uid_t nobody_uid;
+	gid_t nobody_gid;
+
+	tst_reinit();
+	if (argc != 2)
+		tst_brk(TFAIL, "argc is %d, expected 2", argc);
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;
+	/*positive check*/
+	TEST(setgid(nobody_gid));
+	if (TST_RET == -1)
+		tst_res(TFAIL | TTERRNO,
+			"%s setgid(%d) isn't permmit", argv[1], nobody_gid);
+	else
+		tst_res(TPASS, "%s setgid(%d) succeed expectedly",
+			argv[1], nobody_gid);

testcases/kernel/syscalls/prctl/prctl06_execve.c line 46

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+	/*negative check*/
+	TEST(setuid(nobody_uid));
+	if (TST_RET == -1)
+		tst_res(TPASS | TTERRNO,
+			"%s setuid(%d) isn't permmit", argv[1], nobody_uid);
+	else
+		tst_res(TFAIL, " %s setuid(%d) succeed unexpectedly",
+			argv[1], nobody_gid);
+	return 0;
+}

I do not think that this is actually testing the prctl in question. Here we actually check that capabilities were inherited over fork() + exec().

As far as I understand the PR_SET_NO_NEW_PRIVS it has been designed expecially to avoid misuse of capabilities associated with a particular file.

Quoted 7 lines

So the check would have to do:

1. copy the prctl06_execve binary to a $PWD
2. chmod it with S_ISUID, S_ISGID
3. the prct06_execve would be executed under user/group nobody
4. the prct06_execve itself would check if it gained root priviledges

I have seen documention about PR_SET_NO_NEW_PRIVS. I think your way is right. But I have reset this capabilities and only keep CAP_SETGID, so when I set no_new_privs to 1, prctl06_execve inherits CAP_SETGID but not gain CAP_SETUID.

Quoted 5 lines

And we can do the same for capablities as well.

I guess that we would have to format a device and mount it with support for capabilities for the test, since as far as I can tell you cannot usually do neither of set-usr-id or add capabilites to files in /tmp/.

Yes. In /tmp, these make no sense. I will follow by your advise.

Thanks
Yang Xu

author
#5 lore raw

PATCH RESEND 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

---
 include/lapi/prctl.h                          |   5 +
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/prctl/.gitignore    |   1 +
 testcases/kernel/syscalls/prctl/prctl06.c     | 173 ++++++++++++++++++
 .../kernel/syscalls/prctl/prctl06_execve.c    |  65 +++++++
 5 files changed, 245 insertions(+)
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06.c
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06_execve.c
include/lapi/prctl.h +5 -0
index ad0b12bce..54b3da20f 100644
@@ -24,4 +24,9 @@
 # define PR_GET_CHILD_SUBREAPER	37
 #endif
 
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+
 #endif /* LAPI_PRCTL_H__ */
runtest/syscalls +1 -0
index 702d6a8c7..a9cad6748 100644
@@ -860,6 +860,7 @@ prctl02 prctl02
 prctl03 prctl03
 prctl04 prctl04
 prctl05 prctl05
+prctl06 prctl06
 
 pread01 pread01
 pread01_64 pread01_64
testcases/kernel/syscalls/prctl/.gitignore +1 -0
index 9ecaf9854..f52f6f665 100644
@@ -3,3 +3,4 @@
 /prctl03
 /prctl04
 /prctl05
+/prctl06
testcases/kernel/syscalls/prctl/prctl06.c new file +173 -0

173 lines not on this page · raw message

testcases/kernel/syscalls/prctl/prctl06_execve.c new file +65 -0

65 lines not on this page · raw message

Signature · 1 line
2.18.1
#6 lore raw

PATCH RESEND 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Hi!

testcases/kernel/syscalls/prctl/.gitignore line 6

Quoted 11 lines

pread01 pread01
pread01_64 pread01_64

testcases/kernel/syscalls/prctl/.gitignore +1 -0
index 9ecaf9854..f52f6f665 100644
@@ -3,3 +3,4 @@
 /prctl03
 /prctl04
 /prctl05
+/prctl06

Missing prctl06_execve

Quoted 39 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +33 -0
new file mode 100644
index 000000000..9dd82a241
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <[email protected]>
+ *
+ * Test PR_GET_NO_NEW_PRIVS and PR_SET_NO_NEW_PRIVS of prctl(2).
+ *
+ * 1)Return the value of the no_new_privs bit for the calling thread.
+ *  A value of 0 indicates the regular execve(2) behavior.  A value of
+ *  1 indicates execve(2) will operate in the privilege-restricting mode.
+ * 2)With no_new_privs set to 1, diables privilege granting operations
+ *  at execve-time. For example, a process will not be able to execute a
+ *  setuid binary to change their uid or gid if this bit is set. The same
+ *  is true for file capabilities.
+ * 3)The setting of this bit is inherited by children created by fork(2).
+ *  We also check NoNewPrivs field in /proc/[pid]/status if it supports.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/capability.h>
+#include <lapi/prctl.h>
+#include "tst_test.h"
+
+#define IPC_ENV_VAR        "LTP_IPC_PATH"
+#define MNTPOINT           "mntpoint"
+#define TESTBIN            "prctl06_execve"
+#define TEST_REL_BIN_DIR   MNTPOINT"/"

testcases/kernel/syscalls/prctl/prctl06.c line 43

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+#define SUID_MODE          (S_ISUID|S_ISGID|S_IXUSR|S_IXGRP|S_IXOTH)
+
+static int flag = 1;
+static char CapEff[20];
+
+static void check_proc_field(int val, char *name)
+{
+	char path[50];
+	pid_t pid;
+	int field = 0;

Also it would be a bit cleaner if we do:

	if (flag)
		return;

here and called the function unconditionaly down below.

testcases/kernel/syscalls/prctl/prctl06.c line 45

Quoted 2 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +2 -0
+	pid = getpid();
+	sprintf(path, "/proc/%d/status", pid);
                       ^
		       /proc/self/status ?
Quoted 28 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +28 -0
+	TEST(FILE_LINES_SCANF(path, "NoNewPrivs:%d", &field));
+	if (TST_RET == 1) {
+		tst_res(TCONF,
+			"/proc/[pid]/status doesn't support NoNewPrivs field");
+		flag = 0;
+		return;
+	}
+	if (val == field)
+		tst_res(TPASS, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+	else
+		tst_res(TFAIL, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+
+	SAFE_FILE_LINES_SCANF(path, "CapEff:%s", CapEff);
+}
+
+static void check_no_new_privs(int val, char *name)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %d",
+			name, val, val);
+	else
+		tst_res(TFAIL,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			name, val, TST_RET);

testcases/kernel/syscalls/prctl/prctl06.c line 85

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+	if (flag)
+		check_proc_field(val, name);
+}
+
+static void do_prctl(void)
+{
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", CapEff, NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", CapEff, NULL};
+	char *const envp[] = {"LTP_TEST_ENV_VAR=test", ipc_env_var, NULL };

^
This is not really needed here. We use that only in the execve tests...

testcases/kernel/syscalls/prctl/prctl06.c line 93

Quoted 8 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +8 -0
+	int childpid;
+	struct passwd *pw;
+	uid_t nobody_uid;
+	gid_t nobody_gid;
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;

^
This can be done once in test setup

testcases/kernel/syscalls/prctl/prctl06.c line 106

Quoted 12 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +12 -0
+	check_no_new_privs(0, "parent");
+	tst_res(TINFO,
+		"parent process CapEff %s when no new privs was 0", CapEff);
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
+
+	SAFE_CHMOD("prctl06_execve", SUID_MODE);

^
This can be done in setup() as well.

Quoted 23 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +23 -0
+	SAFE_SETGID(nobody_gid);
+	SAFE_SETUID(nobody_uid);
+
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1, "child");
+		execve("prctl06_execve", childargv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		check_no_new_privs(1, "parent");
+		tst_res(TINFO,
+			"parent process CapEff %s when no new privs was 1", CapEff);
+		execve("prctl06_execve", argv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+}
+

testcases/kernel/syscalls/prctl/prctl06.c line 139

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+static void verify_prctl(void)
+{
+	int pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+	tst_reap_children();

No need to reap children here if you do exit(0) the library will reap them for you.

Quoted 62 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +34 -0
+}
+
+static void setup(void)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == 0) {
+		tst_res(TINFO, "kernel supports PR_GET/SET_NO_NEW_PRIVS");
+		SAFE_CP(TESTBIN, TEST_REL_BIN_DIR);
+		return;
+	}
+
+	if (TST_ERR == EINVAL)
+		tst_brk(TCONF,
+			"kernel doesn't support PR_GET/SET_NO_NEW_PRIVS");
+
+	tst_brk(TBROK | TTERRNO,
+		"current environment doesn't permit PR_GET/SET_NO_NEW_PRIVS");
+}
+
+static const char *const resfile[] = {
+	TESTBIN,
+	NULL,
+};
+
+static struct tst_test test = {
+	.resource_files = resfile,
+	.setup = setup,
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +22 -0
new file mode 100644
index 000000000..6b256afae
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{
+	struct passwd *pw;
+	uid_t unknown_uid;
+	gid_t unknown_gid;

testcases/kernel/syscalls/prctl/prctl06_execve.c line 32

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+	char path[50];
+	char CapEff[20];
+	pid_t pid;
+
+	tst_reinit();
+	if (argc != 3)
+		tst_brk(TFAIL, "argc is %d, expected 3", argc);
+
+	pid = getpid();
+	sprintf(path, "/proc/%d/status", pid);
                        ^
			/proc/self/status
Quoted 20 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +20 -0
+	SAFE_FILE_LINES_SCANF(path, "CapEff:%s", CapEff);
+
+	if (strncmp(CapEff, argv[2], sizeof(CapEff)))
+		tst_res(TFAIL,
+			"%s gains root privileges, current CapEff %s, expect %s",
+			argv[1], CapEff, argv[2]);
+	else
+		tst_res(TPASS,
+			"%s doesn't gain root privileges, CapEff %s",
+			argv[1], CapEff);
+
+	pw = SAFE_GETPWNAM("nobody");
+	unknown_uid = pw->pw_uid + 1;
+	unknown_gid = pw->pw_gid + 1;
+
+	TEST(setgid(unknown_gid));
+	if (TST_RET == -1)
+		tst_res(TPASS,
+			"%s setgid(%d) isn't permmit", argv[1], unknown_gid);
+	else

testcases/kernel/syscalls/prctl/prctl06_execve.c line 62

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+		tst_res(TFAIL, "%s setgid(%d) succeed expectedly",
+			argv[1], unknown_gid);
+
+	TEST(setuid(unknown_uid));
+	if (TST_RET == -1)
+		tst_res(TPASS,
+			"%s setuid(%d) isn't permmit", argv[1], unknown_uid);
+	else
+		tst_res(TFAIL, " %s setuid(%d) succeed unexpectedly",
+			argv[1], unknown_gid);

We are executing setuid binary that was created by root here so shouldn't we just check that getuid() and getgid() returns 0?

I guess that we can also chown the file to uid=0 and gid=0 once it has been copied to be 100% sure that the ids are correct in the test setup.

testcases/kernel/syscalls/prctl/prctl06_execve.c line 65

Quoted 2 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +2 -0
+	return 0;
+}

Otherwise the test looks very good.

Also I guess that we need another test that would set the prctl value and check that it cannot be unset. If you are going to do that please do that in a separate file, this one is complex enough...

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#7 lore raw

PATCH RESEND 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Quoted 13 lines · Cyril Hrubis

Hi!

testcases/kernel/syscalls/prctl/.gitignore line 6

Quoted 11 lines

pread01 pread01
pread01_64 pread01_64

testcases/kernel/syscalls/prctl/.gitignore +1 -0
index 9ecaf9854..f52f6f665 100644
@@ -3,3 +3,4 @@
  /prctl03
  /prctl04
  /prctl05
+/prctl06

Missing prctl06_execve

OK.

Quoted 51 lines
Quoted 39 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +33 -0
new file mode 100644
index 000000000..9dd82a241
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu<[email protected]>
+ *
+ * Test PR_GET_NO_NEW_PRIVS and PR_SET_NO_NEW_PRIVS of prctl(2).
+ *
+ * 1)Return the value of the no_new_privs bit for the calling thread.
+ *  A value of 0 indicates the regular execve(2) behavior.  A value of
+ *  1 indicates execve(2) will operate in the privilege-restricting mode.
+ * 2)With no_new_privs set to 1, diables privilege granting operations
+ *  at execve-time. For example, a process will not be able to execute a
+ *  setuid binary to change their uid or gid if this bit is set. The same
+ *  is true for file capabilities.
+ * 3)The setting of this bit is inherited by children created by fork(2).
+ *  We also check NoNewPrivs field in /proc/[pid]/status if it supports.
+ */
+
+#include<errno.h>
+#include<stdio.h>
+#include<stdlib.h>
+#include<sys/prctl.h>
+#include<pwd.h>
+#include<sys/types.h>
+#include<unistd.h>
+#include<sys/capability.h>
+#include<lapi/prctl.h>
+#include "tst_test.h"
+
+#define IPC_ENV_VAR        "LTP_IPC_PATH"
+#define MNTPOINT           "mntpoint"
+#define TESTBIN            "prctl06_execve"
+#define TEST_REL_BIN_DIR   MNTPOINT"/"

testcases/kernel/syscalls/prctl/prctl06.c line 43

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+#define SUID_MODE          (S_ISUID|S_ISGID|S_IXUSR|S_IXGRP|S_IXOTH)
+
+static int flag = 1;
+static char CapEff[20];
+
+static void check_proc_field(int val, char *name)
+{
+	char path[50];
+	pid_t pid;
+	int field = 0;

Also it would be a bit cleaner if we do:

Quoted 5 lines
	if (flag)
		return;

here and called the function unconditionaly down below.

Call check_proc_field() when flag is 1 in check_no_new_privs(). So we have avoideded this situation.

Quoted 5 lines

testcases/kernel/syscalls/prctl/prctl06.c line 45

Quoted 2 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +2 -0
+	pid = getpid();
+	sprintf(path, "/proc/%d/status", pid);
                        ^
		       /proc/self/status ?

Yes.

Quoted 33 lines
Quoted 33 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +33 -0
+	TEST(FILE_LINES_SCANF(path, "NoNewPrivs:%d",&field));
+	if (TST_RET == 1) {
+		tst_res(TCONF,
+			"/proc/[pid]/status doesn't support NoNewPrivs field");
+		flag = 0;
+		return;
+	}
+	if (val == field)
+		tst_res(TPASS, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+	else
+		tst_res(TFAIL, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+
+	SAFE_FILE_LINES_SCANF(path, "CapEff:%s", CapEff);
+}
+
+static void check_no_new_privs(int val, char *name)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %d",
+			name, val, val);
+	else
+		tst_res(TFAIL,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			name, val, TST_RET);
+	if (flag)
+		check_proc_field(val, name);
+}
+
+static void do_prctl(void)
Quoted 8 lines

testcases/kernel/syscalls/prctl/prctl06.c line 85

Quoted 5 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +5 -0
+{
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", CapEff, NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", CapEff, NULL};
+	char *const envp[] = {"LTP_TEST_ENV_VAR=test", ipc_env_var, NULL };

^
This is not really needed here. We use that only in the execve tests...

OK. I got it.

Quoted 11 lines

testcases/kernel/syscalls/prctl/prctl06.c line 93

Quoted 8 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +8 -0
+	int childpid;
+	struct passwd *pw;
+	uid_t nobody_uid;
+	gid_t nobody_gid;
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;

^
This can be done once in test setup

Quoted 15 lines

testcases/kernel/syscalls/prctl/prctl06.c line 106

Quoted 12 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +12 -0
+	check_no_new_privs(0, "parent");
+	tst_res(TINFO,
+		"parent process CapEff %s when no new privs was 0", CapEff);
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
+
+	SAFE_CHMOD("prctl06_execve", SUID_MODE);

^
This can be done in setup() as well.

OK. I will move them into setup() .

Quoted 27 lines
Quoted 27 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +27 -0
+	SAFE_SETGID(nobody_gid);
+	SAFE_SETUID(nobody_uid);
+
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1, "child");
+		execve("prctl06_execve", childargv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		check_no_new_privs(1, "parent");
+		tst_res(TINFO,
+			"parent process CapEff %s when no new privs was 1", CapEff);
+		execve("prctl06_execve", argv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+}
+
+static void verify_prctl(void)
+{
+	int pid;
+
Quoted 8 lines

testcases/kernel/syscalls/prctl/prctl06.c line 139

Quoted 6 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +6 -0
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+	tst_reap_children();

No need to reap children here if you do exit(0) the library will reap them for you.

Yes.

Quoted 66 lines
Quoted 66 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +34 -0
+}
+
+static void setup(void)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == 0) {
+		tst_res(TINFO, "kernel supports PR_GET/SET_NO_NEW_PRIVS");
+		SAFE_CP(TESTBIN, TEST_REL_BIN_DIR);
+		return;
+	}
+
+	if (TST_ERR == EINVAL)
+		tst_brk(TCONF,
+			"kernel doesn't support PR_GET/SET_NO_NEW_PRIVS");
+
+	tst_brk(TBROK | TTERRNO,
+		"current environment doesn't permit PR_GET/SET_NO_NEW_PRIVS");
+}
+
+static const char *const resfile[] = {
+	TESTBIN,
+	NULL,
+};
+
+static struct tst_test test = {
+	.resource_files = resfile,
+	.setup = setup,
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +26 -0
new file mode 100644
index 000000000..6b256afae
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu<[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include<stdlib.h>
+#include<sys/types.h>
+#include<unistd.h>
+#include<errno.h>
+#include<pwd.h>
+#include<stdio.h>
+#include<string.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{
+	struct passwd *pw;
+	uid_t unknown_uid;
+	gid_t unknown_gid;
+	char path[50];
+	char CapEff[20];
+	pid_t pid;
+
Quoted 9 lines

testcases/kernel/syscalls/prctl/prctl06_execve.c line 32

Quoted 6 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +6 -0
+	tst_reinit();
+	if (argc != 3)
+		tst_brk(TFAIL, "argc is %d, expected 3", argc);
+
+	pid = getpid();
+	sprintf(path, "/proc/%d/status", pid);
                         ^
			/proc/self/status

Yes.

Quoted 24 lines
Quoted 24 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +24 -0
+	SAFE_FILE_LINES_SCANF(path, "CapEff:%s", CapEff);
+
+	if (strncmp(CapEff, argv[2], sizeof(CapEff)))
+		tst_res(TFAIL,
+			"%s gains root privileges, current CapEff %s, expect %s",
+			argv[1], CapEff, argv[2]);
+	else
+		tst_res(TPASS,
+			"%s doesn't gain root privileges, CapEff %s",
+			argv[1], CapEff);
+
+	pw = SAFE_GETPWNAM("nobody");
+	unknown_uid = pw->pw_uid + 1;
+	unknown_gid = pw->pw_gid + 1;
+
+	TEST(setgid(unknown_gid));
+	if (TST_RET == -1)
+		tst_res(TPASS,
+			"%s setgid(%d) isn't permmit", argv[1], unknown_gid);
+	else
+		tst_res(TFAIL, "%s setgid(%d) succeed expectedly",
+			argv[1], unknown_gid);
+
+	TEST(setuid(unknown_uid));
Quoted 9 lines

testcases/kernel/syscalls/prctl/prctl06_execve.c line 62

Quoted 6 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +6 -0
+	if (TST_RET == -1)
+		tst_res(TPASS,
+			"%s setuid(%d) isn't permmit", argv[1], unknown_uid);
+	else
+		tst_res(TFAIL, " %s setuid(%d) succeed unexpectedly",
+			argv[1], unknown_gid);

We are executing setuid binary that was created by root here so shouldn't we just check that getuid() and getgid() returns 0?

I try it. whether we set or not set new privs, the getuid() or getgid() return nobody in prctl06_execve. Or, I misunderstand your advise?

Also, my design is that
1. copy the prctl06_execve binary to a $PWD
2. chmod it with S_ISUID, S_ISGID ,prctl06_exeve can be excuted under nobody
3. prctl06 SETGID and SETUID as nobody, set no_new_privs to 1 and excute prctl06_execve
4. the prct06_execve itself would check if it gained root priviledges(check proc/self/status capeff and excute setuid and setgid action )

Quoted 2 lines

I guess that we can also chown the file to uid=0 and gid=0 once it has been copied to be 100% sure that the ids are correct in the test setup.

Yes.

Quoted 8 lines

testcases/kernel/syscalls/prctl/prctl06_execve.c line 65

Quoted 2 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +2 -0
+	return 0;
+}

Otherwise the test looks very good.

Also I guess that we need another test that would set the prctl value and check that it cannot be unset. If you are going to do that please do that in a separate file, this one is complex enough...

OK. I will add this in a separate file.

#8 lore raw

PATCH RESEND 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Hi!

Quoted 5 lines
Quoted 3 lines

We are executing setuid binary that was created by root here so shouldn't we just check that getuid() and getgid() returns 0?

I try it. whether we set or not set new privs, the getuid() or getgid() return nobody in prctl06_execve. Or, I misunderstand your advise?

Looking closely into the manuals the setuid and setgid bits are supposed to set the effective ids, so I guess that the geteuid() and getegid() will return 0 when the process was executed without the prctl().

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#9 lore raw

PATCH RESEND 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Quoted 10 lines

Hi!

Quoted 5 lines
Quoted 3 lines

We are executing setuid binary that was created by root here so shouldn't we just check that getuid() and getgid() returns 0?

I try it. whether we set or not set new privs, the getuid() or getgid() return nobody in prctl06_execve. Or, I misunderstand your advise?

Looking closely into the manuals the setuid and setgid bits are supposed to set the effective ids, so I guess that the geteuid() and getegid() will return 0 when the process was executed without the prctl().

Hi Cyril

Yes. I will remove capeff and setuid,setgid check in my v3 patch. For the prctl value
and check that it cannot be unset, I think it is a error test as manpage said
"prctl() fails with EINVAL when options is PR_SET_NO_NEW_PRIVS& arg2 is not equal to 1 or arg3, arg4, or arg5 is nonzero."

I will add it into prctl02.c. Also, there are many error conditions for prctl. So I think when my prctl07.c are merged into

ltp, I will increase prctl02.c together.

Thanks
Yang Xu

author
#10 lore raw

PATCH v3 1/1 syscalls/prctl06: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

In reply to Cyril Hrubis
---
 include/lapi/prctl.h                          |   5 +
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/prctl/.gitignore    |   2 +
 testcases/kernel/syscalls/prctl/prctl06.c     | 165 ++++++++++++++++++
 .../kernel/syscalls/prctl/prctl06_execve.c    |  52 ++++++
 5 files changed, 225 insertions(+)
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06.c
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06_execve.c
include/lapi/prctl.h +5 -0
index ad0b12bce..54b3da20f 100644
@@ -24,4 +24,9 @@
 # define PR_GET_CHILD_SUBREAPER	37
 #endif
 
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+
 #endif /* LAPI_PRCTL_H__ */
runtest/syscalls +1 -0
index 42c200423..ef7af41b5 100644
@@ -865,6 +865,7 @@ prctl02 prctl02
 prctl03 prctl03
 prctl04 prctl04
 prctl05 prctl05
+prctl06 prctl06
 
 pread01 pread01
 pread01_64 pread01_64
testcases/kernel/syscalls/prctl/.gitignore +2 -0
index 9ecaf9854..ee994086f 100644
@@ -3,3 +3,5 @@
 /prctl03
 /prctl04
 /prctl05
+/prctl06
+/prctl06_execve
testcases/kernel/syscalls/prctl/prctl06.c new file +165 -0

165 lines not on this page · raw message

testcases/kernel/syscalls/prctl/prctl06_execve.c new file +52 -0

52 lines not on this page · raw message

Signature · 1 line
2.18.1
#11 lore raw

PATCH v3 1/1 syscalls/prctl06: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Hi!

testcases/kernel/syscalls/prctl/prctl06.c line 45

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+static uid_t nobody_uid;
+static gid_t nobody_gid;
+static int flag = 1;
+
+static void check_proc_field(int val, char *name)
+{
+	int field = 0;
+	char path[50];
+
+	strcpy(path, "/proc/self/status");

Can't we just define PROC_STATUS "/proc/self/status" and use that instead of copying bytes around at runtime?

Quoted 80 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +80 -0
+	TEST(FILE_LINES_SCANF(path, "NoNewPrivs:%d", &field));
+	if (TST_RET == 1) {
+		tst_res(TCONF,
+			"%s doesn't support NoNewPrivs field", path);
+		flag = 0;
+		return;
+	}
+	if (val == field)
+		tst_res(TPASS, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+	else
+		tst_res(TFAIL, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+}
+
+static void check_no_new_privs(int val, char *name)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %d",
+			name, val, val);
+	else
+		tst_res(TFAIL,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			name, val, TST_RET);
+	if (flag)
+		check_proc_field(val, name);
+}
+
+static void do_prctl(void)
+{
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", NULL};
+	char *const envp[] = {ipc_env_var, NULL };
+	int childpid;
+
+	check_no_new_privs(0, "parent");
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
+
+	SAFE_SETGID(nobody_gid);
+	SAFE_SETUID(nobody_uid);
+
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1, "child");
+		execve("prctl06_execve", childargv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		check_no_new_privs(1, "parent");
+		execve("prctl06_execve", argv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+}
+
+static void verify_prctl(void)
+{
+	int pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+}
+
+static void setup(void)

testcases/kernel/syscalls/prctl/prctl06.c line 135

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+{
+	struct passwd *pw;
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;
+
+	SAFE_CP(TESTBIN, TEST_REL_BIN_DIR);
+	SAFE_CHMOD("prctl06_execve", SUID_MODE);
+	SAFE_CHOWN("prctl06_execve", 0, 0);

You are actually changing and executing the wrong file here. You are working directly with the file in the test temporary directory and not with the file that has been copied over to the mount point.

I guess that we should define BIN_PATH and use it here and also for the execve() above.

Quoted 54 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +29 -0
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == 0) {
+		tst_res(TINFO, "kernel supports PR_GET/SET_NO_NEW_PRIVS");
+		return;
+	}
+
+	if (TST_ERR == EINVAL)
+		tst_brk(TCONF,
+			"kernel doesn't support PR_GET/SET_NO_NEW_PRIVS");
+
+	tst_brk(TBROK | TTERRNO,
+		"current environment doesn't permit PR_GET/SET_NO_NEW_PRIVS");
+}
+
+static const char *const resfile[] = {
+	TESTBIN,
+	NULL,
+};
+
+static struct tst_test test = {
+	.resource_files = resfile,
+	.setup = setup,
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +19 -0
new file mode 100644
index 000000000..92e218020
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{

testcases/kernel/syscalls/prctl/prctl06_execve.c line 29

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+	char path[50];
+	struct passwd *pw;
+
+	pw = SAFE_GETPWNAM("nobody");
+
+	tst_reinit();
+	if (argc != 2)
+		tst_brk(TFAIL, "argc is %d, expected 2", argc);
+
+	strcpy(path, "/proc/self/status");

Here as well, can we use a macro instead?

Quoted 12 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +12 -0
+	TEST(getegid());
+	if (TST_RET == 0)
+		tst_res(TFAIL,
+			"%s getegid() returns 0 unexpectedly, it gains root privileges",
+			argv[1]);
+	if (TST_RET == pw->pw_gid)
+		tst_res(TPASS,
+			"%s getegid() returns nobody, it doesn't gain root privileges",
+			argv[1]);
+
+	TEST(geteuid());
+	if (TST_RET == 0)

testcases/kernel/syscalls/prctl/prctl06_execve.c line 52

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+		tst_res(TFAIL,
+			"%s geteuid() returns 0 unexpectedly, it gains root privileges",
+			argv[1]);
+	if (TST_RET == pw->pw_uid)
+		tst_res(TPASS,
+			"%s geteuid() returns nobody, it doesn't gain root privileges",
+			argv[1]);
+
+	return 0;
+}

The rest looks good.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#12 lore raw

PATCH v3 1/1 syscalls/prctl06: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

Quoted 15 lines

Hi!

testcases/kernel/syscalls/prctl/prctl06.c line 45

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+static uid_t nobody_uid;
+static gid_t nobody_gid;
+static int flag = 1;
+
+static void check_proc_field(int val, char *name)
+{
+	int field = 0;
+	char path[50];
+
+	strcpy(path, "/proc/self/status");

Can't we just define PROC_STATUS "/proc/self/status" and use that instead of copying bytes around at runtime?

Hi

Yes. I move PROC_STATUS and check functions into prctl06.h because we also need to check field after execve. Please see my v4 patch.

Quoted 94 lines
Quoted 80 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +80 -0
+	TEST(FILE_LINES_SCANF(path, "NoNewPrivs:%d",&field));
+	if (TST_RET == 1) {
+		tst_res(TCONF,
+			"%s doesn't support NoNewPrivs field", path);
+		flag = 0;
+		return;
+	}
+	if (val == field)
+		tst_res(TPASS, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+	else
+		tst_res(TFAIL, "%s %s NoNewPrivs field expected %d got %d",
+			name, path, val, field);
+}
+
+static void check_no_new_privs(int val, char *name)
+{
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == val)
+		tst_res(TPASS,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %d",
+			name, val, val);
+	else
+		tst_res(TFAIL,
+			"%s prctl(PR_GET_NO_NEW_PRIVS) expected %d got %ld",
+			name, val, TST_RET);
+	if (flag)
+		check_proc_field(val, name);
+}
+
+static void do_prctl(void)
+{
+	char ipc_env_var[1024];
+	char *const argv[] = {"prctl06_execve", "parent process", NULL};
+	char *const childargv[] = {"prctl06_execve", "child process", NULL};
+	char *const envp[] = {ipc_env_var, NULL };
+	int childpid;
+
+	check_no_new_privs(0, "parent");
+
+	TEST(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+		return;
+	}
+	tst_res(TPASS, "prctl(PR_SET_NO_NEW_PRIVS) succeeded");
+
+	SAFE_SETGID(nobody_gid);
+	SAFE_SETUID(nobody_uid);
+
+	sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR));
+
+	childpid = SAFE_FORK();
+	if (childpid == 0) {
+		check_no_new_privs(1, "child");
+		execve("prctl06_execve", childargv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"child process failed to execute prctl_execve");
+
+	} else {
+		tst_reap_children();
+		check_no_new_privs(1, "parent");
+		execve("prctl06_execve", argv, envp);
+		tst_brk(TFAIL | TTERRNO,
+			"parent process failed to execute prctl_execve");
+	}
+}
+
+static void verify_prctl(void)
+{
+	int pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_prctl();
+		exit(0);
+	}
+}
+
+static void setup(void)

testcases/kernel/syscalls/prctl/prctl06.c line 135

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +10 -0
+{
+	struct passwd *pw;
+
+	pw = SAFE_GETPWNAM("nobody");
+	nobody_uid = pw->pw_uid;
+	nobody_gid = pw->pw_gid;
+
+	SAFE_CP(TESTBIN, TEST_REL_BIN_DIR);
+	SAFE_CHMOD("prctl06_execve", SUID_MODE);
+	SAFE_CHOWN("prctl06_execve", 0, 0);

You are actually changing and executing the wrong file here. You are working directly with the file in the test temporary directory and not with the file that has been copied over to the mount point.

Quoted 2 lines

I guess that we should define BIN_PATH and use it here and also for the execve() above.

Yes .

Quoted 57 lines
Quoted 57 lines
testcases/kernel/syscalls/prctl/prctl06.c new file +29 -0
+	TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+	if (TST_RET == 0) {
+		tst_res(TINFO, "kernel supports PR_GET/SET_NO_NEW_PRIVS");
+		return;
+	}
+
+	if (TST_ERR == EINVAL)
+		tst_brk(TCONF,
+			"kernel doesn't support PR_GET/SET_NO_NEW_PRIVS");
+
+	tst_brk(TBROK | TTERRNO,
+		"current environment doesn't permit PR_GET/SET_NO_NEW_PRIVS");
+}
+
+static const char *const resfile[] = {
+	TESTBIN,
+	NULL,
+};
+
+static struct tst_test test = {
+	.resource_files = resfile,
+	.setup = setup,
+	.test_all = verify_prctl,
+	.forks_child = 1,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.child_needs_reinit = 1,
+};
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +22 -0
new file mode 100644
index 000000000..92e218020
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu<[email protected]>
+ *
+ * dummy program which is used by prctl06 testcase
+ */
+#define TST_NO_DEFAULT_MAIN
+#include<stdlib.h>
+#include<sys/types.h>
+#include<unistd.h>
+#include<errno.h>
+#include<pwd.h>
+#include<stdio.h>
+#include<string.h>
+#include "tst_test.h"
+
+int main(int argc, char **argv)
+{
+	char path[50];
+	struct passwd *pw;
+
Quoted 8 lines

testcases/kernel/syscalls/prctl/prctl06_execve.c line 29

Quoted 7 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +7 -0
+	pw = SAFE_GETPWNAM("nobody");
+
+	tst_reinit();
+	if (argc != 2)
+		tst_brk(TFAIL, "argc is %d, expected 2", argc);
+
+	strcpy(path, "/proc/self/status");

Here as well, can we use a macro instead?

Yes

Quoted 24 lines
Quoted 12 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +12 -0
+	TEST(getegid());
+	if (TST_RET == 0)
+		tst_res(TFAIL,
+			"%s getegid() returns 0 unexpectedly, it gains root privileges",
+			argv[1]);
+	if (TST_RET == pw->pw_gid)
+		tst_res(TPASS,
+			"%s getegid() returns nobody, it doesn't gain root privileges",
+			argv[1]);
+
+	TEST(geteuid());
+	if (TST_RET == 0)

testcases/kernel/syscalls/prctl/prctl06_execve.c line 52

Quoted 10 lines
testcases/kernel/syscalls/prctl/prctl06_execve.c new file +10 -0
+		tst_res(TFAIL,
+			"%s geteuid() returns 0 unexpectedly, it gains root privileges",
+			argv[1]);
+	if (TST_RET == pw->pw_uid)
+		tst_res(TPASS,
+			"%s geteuid() returns nobody, it doesn't gain root privileges",
+			argv[1]);
+
+	return 0;
+}

The rest looks good.

author
#13 lore raw

PATCH 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

In reply to Cyril Hrubis
Quoted 7 lines

Hi!
Can you pretty please resend the prctl06 v2 patch?

I can see it in the patchwork at
http://patchwork.ozlabs.org/patch/1118628/
but that email haven't made it to my mailbox.

Hi cyril

I have resent it again.

ps:I sent it but email date is 2019/07/06 6:48 (my virtual machine date is incorrect I don't notice it )

Thanks
Yang Xu

author
#14 lore raw

PATCH v2 1/1 syscalls/prctl06.c: New test for prctl() with PR_{SET, GET}_NO_NEW_PRIVS

In reply to Cyril Hrubis
---
 include/lapi/prctl.h                          |   5 +
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/prctl/.gitignore    |   1 +
 testcases/kernel/syscalls/prctl/prctl06.c     | 173 ++++++++++++++++++
 .../kernel/syscalls/prctl/prctl06_execve.c    |  65 +++++++
 5 files changed, 245 insertions(+)
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06.c
 create mode 100644 testcases/kernel/syscalls/prctl/prctl06_execve.c
include/lapi/prctl.h +5 -0
index ad0b12bce..54b3da20f 100644
@@ -24,4 +24,9 @@
 # define PR_GET_CHILD_SUBREAPER	37
 #endif
 
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+
 #endif /* LAPI_PRCTL_H__ */
runtest/syscalls +1 -0
index 702d6a8c7..a9cad6748 100644
@@ -860,6 +860,7 @@ prctl02 prctl02
 prctl03 prctl03
 prctl04 prctl04
 prctl05 prctl05
+prctl06 prctl06
 
 pread01 pread01
 pread01_64 pread01_64
testcases/kernel/syscalls/prctl/.gitignore +1 -0
index 9ecaf9854..f52f6f665 100644
@@ -3,3 +3,4 @@
 /prctl03
 /prctl04
 /prctl05
+/prctl06
testcases/kernel/syscalls/prctl/prctl06.c new file +173 -0

173 lines not on this page · raw message

testcases/kernel/syscalls/prctl/prctl06_execve.c new file +65 -0

65 lines not on this page · raw message

Signature · 1 line
2.18.1