diff mbox series

[v2] mount03: Convert to new API

Message ID 20220726070206.266-1-chenhx.fnst@fujitsu.com
State Changes Requested
Headers show
Series [v2] mount03: Convert to new API | expand

Commit Message

chenhx.fnst@fujitsu.com July 26, 2022, 7:02 a.m. UTC
Signed-off-by: Chen Hanxiao <chenhx.fnst@fujitsu.com>
---
v2:
  use octal permissions
  remove long switch of test_rwflag
  skip vfat, exfat and ntfs

 testcases/kernel/syscalls/mount/mount03.c | 560 +++++++++-------------
 1 file changed, 231 insertions(+), 329 deletions(-)
diff mbox series

Patch

diff --git a/testcases/kernel/syscalls/mount/mount03.c b/testcases/kernel/syscalls/mount/mount03.c
index 25f99bbfc..e6395c592 100644
--- a/testcases/kernel/syscalls/mount/mount03.c
+++ b/testcases/kernel/syscalls/mount/mount03.c
@@ -1,389 +1,291 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
+ * Copyright (c) Linux Test Project, 2022
  * Copyright (c) Wipro Technologies Ltd, 2002.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
  */
 
-/*
- * DESCRIPTION
- *	Check for basic mount(2) system call flags.
+/*\
+ * [Description]
+ *
+ * Check for basic mount(2) system call flags.
  *
- *	Verify that mount(2) syscall passes for each flag setting and validate
- *	the flags
- *	1) MS_RDONLY - mount read-only.
- *	2) MS_NODEV - disallow access to device special files.
- *	3) MS_NOEXEC - disallow program execution.
- *	4) MS_SYNCHRONOUS - writes are synced at once.
- *	5) MS_REMOUNT - alter flags of a mounted FS.
- *	6) MS_NOSUID - ignore suid and sgid bits.
- *	7) MS_NOATIME - do not update access times.
+ * Verify that mount(2) syscall passes for each flag setting and validate
+ * the flags
+ *
+ * - MS_RDONLY - mount read-only.
+ * - MS_NODEV - disallow access to device special files.
+ * - MS_NOEXEC - disallow program execution.
+ * - MS_SYNCHRONOUS - writes are synced at once.
+ * - MS_REMOUNT - alter flags of a mounted FS.
+ * - MS_NOSUID - ignore suid and sgid bits.
+ * - MS_NOATIME - do not update access times.
  */
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 
+#define TEMP_FILE	"temp_file"
+#define FILE_MODE	0644
+#define SUID_MODE	0511
+
+#include <stdio.h>
 #include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
 #include <sys/wait.h>
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdlib.h>
 #include <pwd.h>
-#include <unistd.h>
-
-#include "test.h"
-#include "safe_macros.h"
-
-static void setup(void);
-static void cleanup(void);
-static int test_rwflag(int, int);
-
-char *TCID = "mount03";
-int TST_TOTAL = 7;
-
-#define TEMP_FILE	"temp_file"
-#define FILE_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
-#define DIR_MODE	(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \
-			 S_IXGRP|S_IROTH|S_IXOTH)
-#define SUID_MODE	(S_ISUID|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH)
-
-static const char mntpoint[] = "mntpoint";
-static const char *device;
-static const char *fs_type;
-static int fildes;
+#include "tst_test.h"
+#include "tst_safe_file_ops.h"
+#include "lapi/mount.h"
+
+#define MNTPOINT        "mntpoint"
+#define TESTBIN	"mount03_setuid_test"
+#define TCASE_ENTRY(_flags, _do_test)    \
+	{                                \
+		.name = "Flag " #_flags, \
+		.flags = _flags,         \
+		.do_test = _do_test      \
+	}
 
+static int otfd;
 static char write_buffer[BUFSIZ];
 static char read_buffer[BUFSIZ];
-static char path_name[PATH_MAX];
 static char file[PATH_MAX];
-
-long rwflags[] = {
-	MS_RDONLY,
-	MS_NODEV,
-	MS_NOEXEC,
-	MS_SYNCHRONOUS,
-	MS_RDONLY,
-	MS_NOSUID,
-	MS_NOATIME,
+static uid_t nobody_uid;
+static gid_t nobody_gid;
+
+static void test_ms_nosuid(void);
+static void test_ms_rdonly(void);
+static void test_ms_nodev(void);
+static void test_noexec(void);
+static void test_ms_synchronous(void);
+static void test_ms_remount(void);
+static void test_ms_noatime(void);
+
+static struct tcase {
+	char *name;
+	unsigned int flags;
+	void (*do_test)(void);
+} tcases[] = {
+	TCASE_ENTRY(MS_RDONLY, test_ms_rdonly),
+	TCASE_ENTRY(MS_NODEV, test_ms_nodev),
+	TCASE_ENTRY(MS_NOEXEC, test_noexec),
+	TCASE_ENTRY(MS_SYNCHRONOUS, test_ms_synchronous),
+	TCASE_ENTRY(MS_RDONLY, test_ms_remount),
+	TCASE_ENTRY(MS_NOSUID, test_ms_nosuid),
+	TCASE_ENTRY(MS_NOATIME, test_ms_noatime),
 };
 
-int main(int argc, char *argv[])
+static void test_ms_rdonly(void)
 {
-	int lc, i;
-
-	tst_parse_opts(argc, argv, NULL, NULL);
-
-	setup();
+	/* Validate MS_RDONLY flag of mount call */
 
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
+	snprintf(file, PATH_MAX, "%s/tmp", MNTPOINT);
+	TST_EXP_FAIL2(open(file,  O_CREAT | O_RDWR, 0700),
+		      EROFS, "mount(2) passed with flag MS_RDONLY: "
+		      "open fail with EROFS as expected");
 
-		tst_count = 0;
-
-		for (i = 0; i < TST_TOTAL; ++i) {
+	otfd = TST_RET;
+}
 
-			TEST(mount(device, mntpoint, fs_type, rwflags[i],
-				   NULL));
+static void test_ms_nosuid(void)
+{
+	/* Validate MS_NOSUID flag of mount call */
 
-			if (TEST_RETURN != 0) {
-				tst_resm(TFAIL | TTERRNO, "mount(2) failed");
-				continue;
-			}
+	pid_t pid;
+	int status;
 
-			/* Validate the rwflag */
-			if (test_rwflag(i, lc) == 1)
-				tst_resm(TFAIL, "mount(2) failed while"
-					 " validating %ld", rwflags[i]);
-			else
-				tst_resm(TPASS, "mount(2) passed with "
-					 "rwflag = %ld", rwflags[i]);
+	pid = SAFE_FORK();
 
-			TEST(tst_umount(mntpoint));
-			if (TEST_RETURN != 0)
-				tst_brkm(TBROK | TTERRNO, cleanup,
-					 "umount(2) failed for %s", mntpoint);
-		}
+	if (!pid) {
+		SAFE_SETREUID(nobody_uid, nobody_gid);
+		SAFE_EXECLP(TESTBIN, TESTBIN, NULL);
 	}
 
-	cleanup();
-	tst_exit();
+	waitpid(pid, &status, 0);
+	if (WIFEXITED(status)) {
+		/* reset the setup_uid */
+		if (status)
+			tst_res(TPASS, "mount(2) passed with flag MS_NOSUID");
+	} else {
+		tst_res(TFAIL, "mount(2) failed with flag MS_NOSUID");
+	}
 }
 
-/*
- * test_rwflag(int i, int cnt)
- * Validate the mount system call for rwflags.
- */
-int test_rwflag(int i, int cnt)
+static void test_ms_nodev(void)
 {
-	int ret, fd, pid, status;
-	char nobody_uid[] = "nobody";
-	time_t atime;
-	struct passwd *ltpuser;
-	struct stat file_stat;
-	char readbuf[20];
-
-	switch (i) {
-	case 0:
-		/* Validate MS_RDONLY flag of mount call */
-
-		snprintf(file, PATH_MAX, "%stmp", path_name);
-		fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
-		if (fd == -1) {
-			if (errno == EROFS) {
-				return 0;
-			} else {
-				tst_resm(TWARN | TERRNO,
-					 "open didn't fail with EROFS");
-				return 1;
-			}
-		}
-		close(fd);
-		return 1;
-	case 1:
-		/* Validate MS_NODEV flag of mount call */
-
-		snprintf(file, PATH_MAX, "%smynod_%d_%d", path_name, getpid(),
-			 cnt);
-		if (mknod(file, S_IFBLK | 0777, 0) == 0) {
-			fd = open(file, O_RDWR, S_IRWXU);
-			if (fd == -1) {
-				if (errno == EACCES) {
-					return 0;
-				} else {
-					tst_resm(TWARN | TERRNO,
-						 "open didn't fail with EACCES");
-					return 1;
-				}
-			}
-			close(fd);
-		} else {
-			tst_resm(TWARN | TERRNO, "mknod(2) failed to create %s",
-				 file);
-			return 1;
-		}
-		return 1;
-	case 2:
-		/* Validate MS_NOEXEC flag of mount call */
-
-		snprintf(file, PATH_MAX, "%stmp1", path_name);
-		fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
-		if (fd == -1) {
-			tst_resm(TWARN | TERRNO, "opening %s failed", file);
-		} else {
-			close(fd);
-			ret = execlp(file, basename(file), NULL);
-			if ((ret == -1) && (errno == EACCES))
-				return 0;
-		}
-		return 1;
-	case 3:
-		/*
-		 * Validate MS_SYNCHRONOUS flag of mount call.
-		 * Copy some data into data buffer.
-		 */
-
-		strcpy(write_buffer, "abcdefghijklmnopqrstuvwxyz");
-
-		/* Creat a temporary file under above directory */
-		snprintf(file, PATH_MAX, "%s%s", path_name, TEMP_FILE);
-		fildes = open(file, O_RDWR | O_CREAT, FILE_MODE);
-		if (fildes == -1) {
-			tst_resm(TWARN | TERRNO,
-				 "open(%s, O_RDWR|O_CREAT, %#o) failed",
-				 file, FILE_MODE);
-			return 1;
-		}
-
-		/* Write the buffer data into file */
-		if (write(fildes, write_buffer, strlen(write_buffer)) !=
-		    (long)strlen(write_buffer)) {
-			tst_resm(TWARN | TERRNO, "writing to %s failed", file);
-			close(fildes);
-			return 1;
-		}
-
-		/* Set the file ptr to b'nning of file */
-		if (lseek(fildes, 0, SEEK_SET) < 0) {
-			tst_resm(TWARN, "lseek() failed on %s, error="
-				 " %d", file, errno);
-			close(fildes);
-			return 1;
-		}
+	/* Validate MS_NODEV flag of mount call */
+
+	snprintf(file, PATH_MAX, "%s/mynod_%d", MNTPOINT, getpid());
+	if (SAFE_MKNOD(file, S_IFBLK | 0777, 0) == 0) {
+		TST_EXP_FAIL2(open(file, O_RDWR, 0700),
+			      EACCES, "mount(2) passed with flag MS_NODEV: "
+			      "open fail with EACCES as expected");
+		otfd = TST_RET;
+	}
+	SAFE_UNLINK(file);
+}
 
-		/* Read the contents of file */
-		if (read(fildes, read_buffer, sizeof(read_buffer)) > 0) {
-			if (strcmp(read_buffer, write_buffer)) {
-				tst_resm(TWARN, "Data read from %s and written "
-					 "mismatch", file);
-				close(fildes);
-				return 1;
-			} else {
-				close(fildes);
-				return 0;
-			}
-		} else {
-			tst_resm(TWARN | TERRNO, "read() Fails on %s", file);
-			close(fildes);
-			return 1;
+static void test_noexec(void)
+{
+	/* Validate MS_NOEXEC flag of mount call */
+	int ret;
+
+	snprintf(file, PATH_MAX, "%s/tmp1", MNTPOINT);
+	TST_EXP_FD_SILENT(open(file, O_CREAT | O_RDWR, 0700),
+			  "opening %s failed", file);
+	otfd = TST_RET;
+	if (otfd >= 0) {
+		SAFE_CLOSE(otfd);
+		ret = execlp(file, basename(file), NULL);
+		if ((ret == -1) && (errno == EACCES)) {
+			tst_res(TPASS, "mount(2) passed with flag MS_NOEXEC");
+			return;
 		}
+	}
+	tst_brk(TFAIL | TERRNO, "mount(2) failed with flag MS_NOEXEC");
+}
 
-	case 4:
-		/* Validate MS_REMOUNT flag of mount call */
-
-		TEST(mount(device, mntpoint, fs_type, MS_REMOUNT, NULL));
-		if (TEST_RETURN != 0) {
-			tst_resm(TWARN | TTERRNO, "mount(2) failed to remount");
-			return 1;
+static void test_ms_synchronous(void)
+{
+	/*
+	 * Validate MS_SYNCHRONOUS flag of mount call.
+	 * Copy some data into data buffer.
+	 */
+
+	strcpy(write_buffer, "abcdefghijklmnopqrstuvwxyz");
+
+	/* Creat a temporary file under above directory */
+	snprintf(file, PATH_MAX, "%s/%s", MNTPOINT, TEMP_FILE);
+	TST_EXP_FD_SILENT(open(file, O_RDWR | O_CREAT, FILE_MODE),
+			  "open(%s, O_RDWR|O_CREAT, %#o) failed",
+			  file, FILE_MODE);
+	otfd = TST_RET;
+
+	/* Write the buffer data into file */
+	SAFE_WRITE(1, otfd, write_buffer, strlen(write_buffer));
+
+	/* Set the file ptr to b'nning of file */
+	SAFE_LSEEK(otfd, 0, SEEK_SET);
+
+	/* Read the contents of file */
+	if (SAFE_READ(0, otfd, read_buffer, sizeof(read_buffer)) > 0) {
+		if (strcmp(read_buffer, write_buffer)) {
+			tst_brk(TFAIL, "Data read from %s and written "
+				"mismatch", file);
 		} else {
-			snprintf(file, PATH_MAX, "%stmp2", path_name);
-			fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
-			if (fd == -1) {
-				tst_resm(TWARN, "open(%s) on readonly "
-					 "filesystem passed", file);
-				return 1;
-			} else {
-				close(fd);
-				return 0;
-			}
-		}
-	case 5:
-		/* Validate MS_NOSUID flag of mount call */
-
-		snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name);
-
-		pid = fork();
-		switch (pid) {
-		case -1:
-			tst_resm(TBROK | TERRNO, "fork failed");
-			return 1;
-		case 0:
-			ltpuser = getpwnam(nobody_uid);
-			if (setreuid(ltpuser->pw_uid, ltpuser->pw_uid) == -1)
-				tst_resm(TWARN | TERRNO,
-					 "seteuid() failed to change euid to %d",
-					 ltpuser->pw_uid);
-
-			execlp(file, basename(file), NULL);
-			exit(1);
-		default:
-			waitpid(pid, &status, 0);
-			if (WIFEXITED(status)) {
-				/* reset the setup_uid */
-				if (status)
-					return 0;
-			}
-			return 1;
-		}
-	case 6:
-		/* Validate MS_NOATIME flag of mount call */
-
-		snprintf(file, PATH_MAX, "%satime", path_name);
-		fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
-		if (fd == -1) {
-			tst_resm(TWARN | TERRNO, "opening %s failed", file);
-			return 1;
-		}
-
-		if (write(fd, "TEST_MS_NOATIME", 15) != 15) {
-			tst_resm(TWARN | TERRNO, "write %s failed", file);
-			close(fd);
-			return 1;
-		}
-
-		if (fstat(fd, &file_stat) == -1) {
-			tst_resm(TWARN | TERRNO, "stat %s failed #1", file);
-			close(fd);
-			return 1;
-		}
-
-		atime = file_stat.st_atime;
-
-		sleep(1);
-
-		if (read(fd, readbuf, sizeof(readbuf)) == -1) {
-			tst_resm(TWARN | TERRNO, "read %s failed", file);
-			close(fd);
-			return 1;
+			SAFE_CLOSE(otfd);
+			tst_res(TPASS, "mount(2) passed with flag MS_SYNCHRONOUS");
+			return;
 		}
+	} else {
+		tst_brk(TFAIL | TERRNO, "read() Fails on %s", file);
+	}
+}
 
-		if (fstat(fd, &file_stat) == -1) {
-			tst_resm(TWARN | TERRNO, "stat %s failed #2", file);
-			close(fd);
-			return 1;
-		}
-		close(fd);
-
-		if (file_stat.st_atime != atime) {
-			tst_resm(TWARN, "access time is updated");
-			return 1;
-		}
-		return 0;
+static void test_ms_remount(void)
+{
+	/* Validate MS_REMOUNT flag of mount call */
+
+	TEST(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, MS_REMOUNT, NULL));
+	if (TST_RET != 0) {
+		tst_brk(TFAIL | TTERRNO, "mount(2) failed to remount");
+	} else {
+		snprintf(file, PATH_MAX, "%s/tmp2", MNTPOINT);
+		TEST(open(file, O_CREAT | O_RDWR, 0700));
+		otfd = TST_RET;
+		if (otfd == -1) {
+			tst_res(TFAIL, "open(%s) on readonly "
+				"filesystem passed", file);
+		} else
+			tst_res(TPASS, "mount(2) passed with flag MS_REMOUNT");
 	}
-	return 0;
 }
 
-static void setup(void)
+static void test_ms_noatime(void)
 {
-	char path[PATH_MAX];
+	/* Validate MS_NOATIME flag of mount call */
+	time_t atime;
 	struct stat file_stat;
+	char readbuf[20];
 
-	tst_sig(FORK, DEF_HANDLER, cleanup);
-
-	tst_require_root();
-
-	tst_tmpdir();
-
-	fs_type = tst_dev_fs_type();
-	device = tst_acquire_device(cleanup);
+	snprintf(file, PATH_MAX, "%s/atime", MNTPOINT);
+	TST_EXP_FD_SILENT(open(file, O_CREAT | O_RDWR, 0700));
+	otfd = TST_RET;
 
-	if (!device)
-		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
+	SAFE_WRITE(1, otfd, "TEST_MS_NOATIME", 15);
 
-	tst_mkfs(cleanup, device, fs_type, NULL, NULL);
+	SAFE_FSTAT(otfd, &file_stat);
 
-	SAFE_MKDIR(cleanup, mntpoint, DIR_MODE);
+	atime = file_stat.st_atime;
 
-	if (getcwd(path_name, sizeof(path_name)) == NULL)
-		tst_brkm(TBROK, cleanup, "getcwd failed");
+	sleep(1);
 
-	if (chmod(path_name, DIR_MODE) != 0)
-		tst_brkm(TBROK, cleanup, "chmod(%s, %#o) failed",
-			 path_name, DIR_MODE);
+	SAFE_READ(0, otfd, readbuf, sizeof(readbuf));
 
-	strncpy(path, path_name, PATH_MAX);
-	snprintf(path_name, PATH_MAX, "%s/%s/", path, mntpoint);
+	SAFE_FSTAT(otfd, &file_stat);
 
-	SAFE_MOUNT(cleanup, device, mntpoint, fs_type, 0, NULL);
-	TST_RESOURCE_COPY(cleanup, "mount03_setuid_test", path_name);
+	if (file_stat.st_atime != atime) {
+		tst_res(TFAIL, "access time is updated");
+		return;
+	}
+	tst_res(TPASS, "mount(2) passed with flag MS_NOATIME");
+}
 
-	snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name);
-	SAFE_STAT(cleanup, file, &file_stat);
+static void run(unsigned int n)
+{
+	struct tcase *tc = &tcases[n];
 
-	if (file_stat.st_mode != SUID_MODE &&
-	    chmod(file, SUID_MODE) < 0)
-		tst_brkm(TBROK, cleanup,
-			 "setuid for setuid_test failed");
-	SAFE_UMOUNT(cleanup, mntpoint);
+	TEST(mount(tst_device->dev, MNTPOINT, tst_device->fs_type,
+		   tc->flags, NULL));
+	if (tc->do_test)
+		tc->do_test();
 
-	TEST_PAUSE;
+	if (otfd >= 0)
+		SAFE_CLOSE(otfd);
+	if (tst_is_mounted(MNTPOINT))
+		SAFE_UMOUNT(MNTPOINT);
 }
 
 static void cleanup(void)
 {
-	if (device)
-		tst_release_device(device);
+	if (otfd > -1)
+		SAFE_CLOSE(otfd);
+}
+
+static void setup(void)
+{
+	struct stat file_stat = {0};
+	struct passwd *ltpuser = SAFE_GETPWNAM("nobody");
 
-	tst_rmdir();
+	nobody_uid = ltpuser->pw_uid;
+	nobody_gid = ltpuser->pw_gid;
+	snprintf(file, PATH_MAX, "%s/mount03_setuid_test", MNTPOINT);
+	SAFE_STAT(MNTPOINT, &file_stat);
+	if (file_stat.st_mode != SUID_MODE &&
+	    chmod(MNTPOINT, SUID_MODE) < 0)
+		tst_brk(TBROK, "setuid for setuid_test failed");
 }
+
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(tcases),
+	.test = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.format_device = 1,
+	.resource_files = (const char *const[]) {
+		"mount03_setuid_test",
+		NULL,
+	},
+	.forks_child = 1,
+	.mntpoint = MNTPOINT,
+	.all_filesystems = 1,
+	.skip_filesystems = (const char *const []){
+		"exfat",
+		"vfat",
+		"ntfs",
+		NULL
+	},
+};