[LTP] [PATCH v1] syscalls/mount07: Add new test case for MS_NOSYMFOLLOW

Yang Xu xuyang2018.jy@fujitsu.com
Tue Jan 31 10:11:58 CET 2023


Fixes:#960
Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
 include/lapi/mount.h                       |   4 +
 runtest/syscalls                           |   1 +
 testcases/kernel/syscalls/mount/.gitignore |   1 +
 testcases/kernel/syscalls/mount/mount07.c  | 177 +++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 testcases/kernel/syscalls/mount/mount07.c

diff --git a/include/lapi/mount.h b/include/lapi/mount.h
index 66e1d1319..c1af944fe 100644
--- a/include/lapi/mount.h
+++ b/include/lapi/mount.h
@@ -33,4 +33,8 @@
 # define UMOUNT_NOFOLLOW 8
 #endif
 
+#ifndef MS_NOSYMFOLLOW
+# define MS_NOSYMFOLLOW 256
+#endif
+
 #endif /* LAPI_MOUNT_H__ */
diff --git a/runtest/syscalls b/runtest/syscalls
index ae37a1192..81c30402b 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -804,6 +804,7 @@ mount03 mount03
 mount04 mount04
 mount05 mount05
 mount06 mount06
+mount07 mount07
 
 mount_setattr01 mount_setattr01
 
diff --git a/testcases/kernel/syscalls/mount/.gitignore b/testcases/kernel/syscalls/mount/.gitignore
index f92600d36..80885dbf0 100644
--- a/testcases/kernel/syscalls/mount/.gitignore
+++ b/testcases/kernel/syscalls/mount/.gitignore
@@ -5,3 +5,4 @@
 /mount04
 /mount05
 /mount06
+/mount07
diff --git a/testcases/kernel/syscalls/mount/mount07.c b/testcases/kernel/syscalls/mount/mount07.c
new file mode 100644
index 000000000..eb3fb55a0
--- /dev/null
+++ b/testcases/kernel/syscalls/mount/mount07.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * It is a basic test for MS_NOSYMFOLLOW mount option and is copied
+ * from kernel selftests nosymfollow-test.c.
+ *
+ * It tests to make sure that symlink traversal fails with ELOOP when
+ * 'nosymfollow' is set, but symbolic links can still be created, and
+ * readlink(2) and realpath(3) still work properly. It also verifies
+ * that statfs(2) correctly returns ST_NOSYMFOLLOW.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <stdbool.h>
+#include "tst_test.h"
+#include "lapi/mount.h"
+
+#ifndef ST_NOSYMFOLLOW
+# define ST_NOSYMFOLLOW 0x2000
+#endif
+
+#define MNTPOINT "mntpoint"
+
+static char test_file[PATH_MAX];
+static char link_file[PATH_MAX];
+static char temp_link_file[PATH_MAX];
+static int flag;
+
+static void setup_symlink(void)
+{
+	int fd;
+
+	fd = SAFE_CREAT(test_file, O_RDWR);
+	SAFE_SYMLINK(test_file, link_file);
+	SAFE_CLOSE(fd);
+	flag = 1;
+}
+
+static void test_link_traversal(bool nosymfollow)
+{
+	if (nosymfollow) {
+		TST_EXP_FAIL2(open(link_file, 0, O_RDWR), ELOOP,
+				"open(%s, 0, O_RDWR)", link_file);
+	} else {
+		TST_EXP_FD(open(link_file, 0, O_RDWR));
+	}
+
+	if (TST_RET > 0)
+		SAFE_CLOSE(TST_RET);
+}
+
+static void test_readlink(void)
+{
+	char buf[4096];
+
+	memset(buf, 0, 4096);
+	TST_EXP_POSITIVE(readlink(link_file, buf, sizeof(buf)),
+			"readlink(%s, buf, %ld)", link_file, sizeof(buf));
+	if (strcmp(buf, test_file) != 0) {
+		tst_res(TFAIL, "readlink strcmp failed, %s, %s",
+				buf, test_file);
+	} else {
+		tst_res(TPASS, "readlink strcmp succeeded");
+	}
+}
+
+static void test_realpath(void)
+{
+	TESTPTR(realpath(link_file, NULL));
+
+	if (!TST_RET_PTR) {
+		tst_res(TFAIL | TERRNO, "realpath failed");
+		return;
+	}
+
+	if (strcmp(TST_RET_PTR, test_file) != 0) {
+		tst_res(TFAIL, "realpath strcmp failed, %s, %s",
+				(char *)TST_RET_PTR, test_file);
+	} else {
+		tst_res(TPASS, "realpath strcmp succeeded");
+	}
+}
+
+static void test_cycle_link(void)
+{
+	TST_EXP_PASS(symlink(test_file, temp_link_file), "symlink(%s, %s)",
+			test_file, temp_link_file);
+	TST_EXP_PASS(unlink(temp_link_file));
+}
+
+static void test_statfs(bool nosymfollow)
+{
+	struct statfs buf;
+
+	SAFE_STATFS(MNTPOINT, &buf);
+	if (buf.f_flags & ST_NOSYMFOLLOW) {
+		tst_res(nosymfollow ? TPASS : TFAIL, "ST_NOSYMFOLLOW set on %s",
+				MNTPOINT);
+	} else {
+		tst_res(nosymfollow ? TFAIL : TPASS, "ST_NOSYMFOLLOW not set on %s",
+				MNTPOINT);
+	}
+}
+
+static void setup(void)
+{
+	char *tmpdir = tst_get_tmpdir();
+
+	snprintf(test_file, PATH_MAX, "%s/%s/test_file", tst_get_tmpdir(),
+			MNTPOINT);
+	snprintf(link_file, PATH_MAX, "%s/%s/link_file", tst_get_tmpdir(),
+			MNTPOINT);
+	snprintf(temp_link_file, PATH_MAX, "%s/%s/temp_link_file",
+			tst_get_tmpdir(), MNTPOINT);
+	free(tmpdir);
+}
+
+static void cleanup(void)
+{
+	if (tst_is_mounted(MNTPOINT))
+		SAFE_UMOUNT(MNTPOINT);
+}
+
+static void run_tests(bool nosymfollow)
+{
+	test_link_traversal(nosymfollow);
+	test_readlink();
+	test_realpath();
+	test_cycle_link();
+	test_statfs(nosymfollow);
+}
+
+static void run(void)
+{
+	tst_res(TINFO, "Testing behaviour when not setting MS_NOSYMFOLLOW");
+
+	TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type,
+		0, NULL));
+	if (!flag || !strcmp(tst_device->fs_type, "tmpfs"))
+		setup_symlink();
+	run_tests(false);
+
+	tst_res(TINFO, "Testing behaviour when setting MS_NOSYMFOLLOW");
+	TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type,
+		MS_REMOUNT | MS_NOSYMFOLLOW, NULL));
+	run_tests(true);
+
+	SAFE_UMOUNT(MNTPOINT);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.forks_child = 1,
+	.needs_root = 1,
+	.min_kver = "5.10",
+	.format_device = 1,
+	.mntpoint = MNTPOINT,
+	.all_filesystems = 1,
+	.skip_filesystems = (const char *const []){
+		"exfat",
+		"vfat",
+		"ntfs",
+		NULL
+	},
+};
-- 
2.31.1



More information about the ltp mailing list