[LTP] [PATCH v3 3/9] Rewrite userns03.c using new LTP API

Andrea Cervesato andrea.cervesato@suse.de
Fri Mar 25 10:36:20 CET 2022


Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.de>
---
 testcases/kernel/containers/userns/userns03.c | 284 ++++++++----------
 1 file changed, 129 insertions(+), 155 deletions(-)

diff --git a/testcases/kernel/containers/userns/userns03.c b/testcases/kernel/containers/userns/userns03.c
index be511fec8..9a6f1b54a 100644
--- a/testcases/kernel/containers/userns/userns03.c
+++ b/testcases/kernel/containers/userns/userns03.c
@@ -1,24 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) Huawei Technologies Co., Ltd., 2015
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version. This program is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details. You should have received a copy of the GNU
- * General Public License along with this program.
+ * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
  */
 
-/*
- * Verify that:
- * /proc/PID/uid_map and /proc/PID/gid_map contains three values separated by
- * white space:
+/*\
+ * [Description]
+ *
+ * Verify that /proc/PID/uid_map and /proc/PID/gid_map contains three values
+ * separated by white space:
+ *
  * ID-inside-ns   ID-outside-ns   length
  *
  * ID-outside-ns is interpreted according to which process is opening the file.
+ *
  * If the process opening the file is in the same user namespace as the process
  * PID, then ID-outside-ns is defined with respect to the parent user namespace.
+ *
  * If the process opening the file is in a different user namespace, then
  * ID-outside-ns is defined with respect to the user namespace of the process
  * opening the file.
@@ -26,29 +24,16 @@
  * The string "deny" would be written to /proc/self/setgroups before GID
  * check if setgroups is allowed, see kernel commits:
  *
- *   commit 9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8
- *   Author: Eric W. Biederman <ebiederm@xmission.com>
- *   Date:   Tue Dec 2 12:27:26 2014 -0600
- *     userns: Add a knob to disable setgroups on a per user namespace basis
- *
- *   commit 66d2f338ee4c449396b6f99f5e75cd18eb6df272
- *   Author: Eric W. Biederman <ebiederm@xmission.com>
- *   Date:   Fri Dec 5 19:36:04 2014 -0600
- *     userns: Allow setting gid_maps without privilege when setgroups is disabled
- *
+ * * 9cc46516ddf4 ("userns: Add a knob to disable setgroups on a per user namespace basis")
+ * * 66d2f338ee4c ("userns: Allow setting gid_maps without privilege when setgroups is disabled")
  */
 
 #define _GNU_SOURCE
-#include <sys/wait.h>
-#include <assert.h>
+
 #include <stdio.h>
-#include <stdlib.h>
 #include <stdbool.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include "userns_helper.h"
-#include "test.h"
+#include "common.h"
+#include "tst_test.h"
 
 #define CHILD1UID 0
 #define CHILD1GID 0
@@ -57,16 +42,16 @@
 #define UID_MAP 0
 #define GID_MAP 1
 
-char *TCID = "user_namespace3";
-int TST_TOTAL = 1;
-static int cpid1, parentuid, parentgid;
+static int cpid1;
+static int parentuid;
+static int parentgid;
 
 /*
  * child_fn1() - Inside a new user namespace
  */
 static int child_fn1(void)
 {
-	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
+	TST_CHECKPOINT_WAIT(0);
 	return 0;
 }
 
@@ -75,161 +60,150 @@ static int child_fn1(void)
  */
 static int child_fn2(void)
 {
-	int exit_val = 0;
 	int uid, gid;
 	char cpid1uidpath[BUFSIZ];
 	char cpid1gidpath[BUFSIZ];
 	int idinsidens, idoutsidens, length;
 
-	TST_SAFE_CHECKPOINT_WAIT(NULL, 1);
+	TST_CHECKPOINT_WAIT(1);
 
 	uid = geteuid();
 	gid = getegid();
 
-	if (uid != CHILD2UID || gid != CHILD2GID) {
-		printf("unexpected uid=%d gid=%d\n", uid, gid);
-		exit_val = 1;
-	}
+	tst_res(TINFO, "uid=%d, gid=%d", uid, gid);
+
+	if (uid != CHILD2UID || gid != CHILD2GID)
+		tst_res(TFAIL, "unexpected uid=%d gid=%d", uid, gid);
+	else
+		tst_res(TPASS, "expected uid and gid");
 
-	/*Get the uid parameters of the child_fn2 process.*/
-	SAFE_FILE_SCANF(NULL, "/proc/self/uid_map", "%d %d %d", &idinsidens,
-		&idoutsidens, &length);
+	/* Get the uid parameters of the child_fn2 process */
+	SAFE_FILE_SCANF("/proc/self/uid_map", "%d %d %d", &idinsidens, &idoutsidens, &length);
 
 	/* map file format:ID-inside-ns   ID-outside-ns   length
-	If the process opening the file is in the same user namespace as
-	the process PID, then ID-outside-ns is defined with respect to the
-	 parent user namespace.*/
-	if (idinsidens != CHILD2UID || idoutsidens != parentuid) {
-		printf("child_fn2 checks /proc/cpid2/uid_map:\n");
-		printf("unexpected: idinsidens=%d idoutsidens=%d\n",
-			idinsidens, idoutsidens);
-		exit_val = 1;
-	}
+	 * If the process opening the file is in the same user namespace as
+	 * the process PID, then ID-outside-ns is defined with respect to the
+	 * parent user namespace
+	 */
+	tst_res(TINFO, "child2 checks /proc/cpid2/uid_map");
+
+	if (idinsidens != CHILD2UID || idoutsidens != parentuid)
+		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
+	else
+		tst_res(TPASS, "expected namespaces IDs");
 
 	sprintf(cpid1uidpath, "/proc/%d/uid_map", cpid1);
-	SAFE_FILE_SCANF(NULL, cpid1uidpath, "%d %d %d", &idinsidens,
-		&idoutsidens, &length);
+	SAFE_FILE_SCANF(cpid1uidpath, "%d %d %d", &idinsidens, &idoutsidens, &length);
 
 	/* If the process opening the file is in a different user namespace,
-	then ID-outside-ns is defined with respect to the user namespace
-	of the process opening the file.*/
-	if (idinsidens != CHILD1UID || idoutsidens != CHILD2UID) {
-		printf("child_fn2 checks /proc/cpid1/uid_map:\n");
-		printf("unexpected: idinsidens=%d idoutsidens=%d\n",
-			idinsidens, idoutsidens);
-		exit_val = 1;
-	}
+	 * then ID-outside-ns is defined with respect to the user namespace
+	 * of the process opening the file
+	 */
+	tst_res(TINFO, "child2 checks /proc/cpid1/uid_map");
+
+	if (idinsidens != CHILD1UID || idoutsidens != CHILD2UID)
+		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
+	else
+		tst_res(TPASS, "expected namespaces IDs");
 
 	sprintf(cpid1gidpath, "/proc/%d/gid_map", cpid1);
-	SAFE_FILE_SCANF(NULL, "/proc/self/gid_map", "%d %d %d",
-		 &idinsidens, &idoutsidens, &length);
-
-	if (idinsidens != CHILD2GID || idoutsidens != parentgid) {
-		printf("child_fn2 checks /proc/cpid2/gid_map:\n");
-		printf("unexpected: idinsidens=%d idoutsidens=%d\n",
-			idinsidens, idoutsidens);
-		exit_val = 1;
-	}
+	SAFE_FILE_SCANF("/proc/self/gid_map", "%d %d %d", &idinsidens, &idoutsidens, &length);
 
-	SAFE_FILE_SCANF(NULL, cpid1gidpath, "%d %d %d", &idinsidens,
-		&idoutsidens, &length);
+	tst_res(TINFO, "child2 checks /proc/cpid2/gid_map");
 
-	if (idinsidens != CHILD1GID || idoutsidens != CHILD2GID) {
-		printf("child_fn1 checks /proc/cpid1/gid_map:\n");
-		printf("unexpected: idinsidens=%d idoutsidens=%d\n",
-			idinsidens, idoutsidens);
-		exit_val = 1;
-	}
+	if (idinsidens != CHILD2GID || idoutsidens != parentgid)
+		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
+	else
+		tst_res(TPASS, "expected namespaces IDs");
 
-	TST_SAFE_CHECKPOINT_WAKE(NULL, 0);
-	TST_SAFE_CHECKPOINT_WAKE(NULL, 1);
-	return exit_val;
-}
+	SAFE_FILE_SCANF(cpid1gidpath, "%d %d %d", &idinsidens, &idoutsidens, &length);
 
-static void cleanup(void)
-{
-	tst_rmdir();
+	tst_res(TINFO, "child1 checks /proc/cpid1/gid_map");
+
+	if (idinsidens != CHILD1GID || idoutsidens != CHILD2GID)
+		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
+	else
+		tst_res(TPASS, "expected namespaces IDs");
+
+	TST_CHECKPOINT_WAKE(0);
+	TST_CHECKPOINT_WAKE(1);
+
+	return 0;
 }
 
 static void setup(void)
 {
 	check_newuser();
-	tst_tmpdir();
-	TST_CHECKPOINT_INIT(NULL);
 }
 
-int main(int argc, char *argv[])
+static void run(void)
 {
 	pid_t cpid2;
 	char path[BUFSIZ];
-	int lc;
 	int fd;
 	int ret;
 
-	tst_parse_opts(argc, argv, NULL, NULL);
-	setup();
-
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
-		tst_count = 0;
-
-		parentuid = geteuid();
-		parentgid = getegid();
-
-		cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD,
-			(void *)child_fn1, NULL);
-		if (cpid1 < 0)
-			tst_brkm(TBROK | TERRNO, cleanup,
-				"cpid1 clone failed");
-
-		cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD,
-			(void *)child_fn2, NULL);
-		if (cpid2 < 0)
-			tst_brkm(TBROK | TERRNO, cleanup,
-				"cpid2 clone failed");
-
-		if (access("/proc/self/setgroups", F_OK) == 0) {
-			sprintf(path, "/proc/%d/setgroups", cpid1);
-			fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644);
-			SAFE_WRITE(cleanup, 1, fd, "deny", 4);
-			SAFE_CLOSE(cleanup, fd);
-			/* If the setgroups file has the value "deny",
-			 * then the setgroups(2) system call can't
-			 * subsequently be reenabled (by writing "allow" to
-			 * the file) in this user namespace.  (Attempts to
-			 * do so will fail with the error EPERM.)
-			*/
-
-			/* test that setgroups can't be re-enabled */
-			fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644);
-			ret = write(fd, "allow", 5);
-
-			if (ret != -1) {
-				tst_brkm(TBROK | TERRNO, cleanup,
-					"write action should fail");
-			} else if (errno != EPERM) {
-				tst_brkm(TBROK | TERRNO, cleanup,
-					"unexpected error: \n");
-			}
-			SAFE_CLOSE(cleanup, fd);
-			tst_resm(TPASS, "setgroups can't be re-enabled");
-
-			sprintf(path, "/proc/%d/setgroups", cpid2);
-			fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644);
-			SAFE_WRITE(cleanup, 1, fd, "deny", 4);
-			SAFE_CLOSE(cleanup, fd);
-		}
-
-		updatemap(cpid1, UID_MAP, CHILD1UID, parentuid, cleanup);
-		updatemap(cpid2, UID_MAP, CHILD2UID, parentuid, cleanup);
-
-		updatemap(cpid1, GID_MAP, CHILD1GID, parentgid, cleanup);
-		updatemap(cpid2, GID_MAP, CHILD2GID, parentgid, cleanup);
-
-		TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 1);
-
-		tst_record_childstatus(cleanup, cpid1);
-		tst_record_childstatus(cleanup, cpid2);
+	parentuid = geteuid();
+	parentgid = getegid();
+
+	cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn1, NULL);
+	if (cpid1 < 0)
+		tst_brk(TBROK | TTERRNO, "cpid1 clone failed");
+
+	cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn2, NULL);
+	if (cpid2 < 0)
+		tst_brk(TBROK | TTERRNO, "cpid2 clone failed");
+
+	if (access("/proc/self/setgroups", F_OK) == 0) {
+		sprintf(path, "/proc/%d/setgroups", cpid1);
+
+		fd = SAFE_OPEN(path, O_WRONLY, 0644);
+		SAFE_WRITE(1, fd, "deny", 4);
+		SAFE_CLOSE(fd);
+
+		/* If the setgroups file has the value "deny",
+		 * then the setgroups(2) system call can't
+		 * subsequently be reenabled (by writing "allow" to
+		 * the file) in this user namespace.  (Attempts to
+		 * do so will fail with the error EPERM.)
+		 */
+
+		/* test that setgroups can't be re-enabled */
+		fd = SAFE_OPEN(path, O_WRONLY, 0644);
+		ret = write(fd, "allow", 5);
+
+		if (ret != -1)
+			tst_brk(TBROK, "write action should fail");
+		else if (errno != EPERM)
+			tst_brk(TBROK | TTERRNO, "unexpected error");
+
+		SAFE_CLOSE(fd);
+
+		tst_res(TPASS, "setgroups can't be re-enabled");
+
+		sprintf(path, "/proc/%d/setgroups", cpid2);
+
+		fd = SAFE_OPEN(path, O_WRONLY, 0644);
+		SAFE_WRITE(1, fd, "deny", 4);
+		SAFE_CLOSE(fd);
 	}
-	cleanup();
-	tst_exit();
+
+	updatemap(cpid1, UID_MAP, CHILD1UID, parentuid);
+	updatemap(cpid2, UID_MAP, CHILD2UID, parentuid);
+
+	updatemap(cpid1, GID_MAP, CHILD1GID, parentgid);
+	updatemap(cpid2, GID_MAP, CHILD2GID, parentgid);
+
+	TST_CHECKPOINT_WAKE_AND_WAIT(1);
 }
+
+static struct tst_test test = {
+	.setup = setup,
+	.test_all = run,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_USER_NS",
+		NULL,
+	},
+};
-- 
2.35.1



More information about the ltp mailing list