1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
4 * Author: Dai Shili <[email protected]>
5 * Author: Chen Hanxiao <[email protected]>
6 */
7
8 /*\
9 * [Description]
10 *
11 * Basic mount_setattr() test.
12 * Test whether the basic mount attributes are set correctly.
13 *
14 * Verify some MOUNT_SETATTR(2) attributes:
15 *
16 * - MOUNT_ATTR_RDONLY - makes the mount read-only
17 * - MOUNT_ATTR_NOSUID - causes the mount not to honor the
18 * set-user-ID and set-group-ID mode bits and file capabilities
19 * when executing programs.
20 * - MOUNT_ATTR_NODEV - prevents access to devices on this mount
21 * - MOUNT_ATTR_NOEXEC - prevents executing programs on this mount
22 * - MOUNT_ATTR_NOSYMFOLLOW - prevents following symbolic links
23 * on this mount
24 * - MOUNT_ATTR_NODIRATIME - prevents updating access time for
25 * directories on this mount
26 *
27 * The functionality was added in v5.12.
28 */
29
30 #define _GNU_SOURCE
31
32 #include <sys/statvfs.h>
33 #include "tst_test.h"
34 #include "lapi/fsmount.h"
35
36 #define MNTPOINT "mntpoint"
37 #define OT_MNTPOINT "ot_mntpoint"
38 #define TCASE_ENTRY(attrs, exp_attrs) \
39 { \
40 .name = #attrs, \
41 .mount_attrs = attrs, \
42 .expect_attrs = exp_attrs \
43 }
44
45 static int mount_flag, otfd = -1;
46
47 static struct tcase {
48 char *name;
49 unsigned int mount_attrs;
50 unsigned int expect_attrs;
51 } tcases[] = {
52 TCASE_ENTRY(MOUNT_ATTR_RDONLY, ST_RDONLY),
53 TCASE_ENTRY(MOUNT_ATTR_NOSUID, ST_NOSUID),
54 TCASE_ENTRY(MOUNT_ATTR_NODEV, ST_NODEV),
55 TCASE_ENTRY(MOUNT_ATTR_NOEXEC, ST_NOEXEC),
56 TCASE_ENTRY(MOUNT_ATTR_NOSYMFOLLOW, ST_NOSYMFOLLOW),
57 TCASE_ENTRY(MOUNT_ATTR_NODIRATIME, ST_NODIRATIME),
58 };
59
cleanup(void)60 static void cleanup(void)
61 {
62 if (otfd > -1)
63 SAFE_CLOSE(otfd);
64 if (mount_flag)
65 SAFE_UMOUNT(OT_MNTPOINT);
66 }
67
setup(void)68 static void setup(void)
69 {
70 fsopen_supported_by_kernel();
71 struct stat st = {0};
72
73 if (stat(OT_MNTPOINT, &st) == -1)
74 SAFE_MKDIR(OT_MNTPOINT, 0777);
75 }
76
run(unsigned int n)77 static void run(unsigned int n)
78 {
79 struct tcase *tc = &tcases[n];
80 struct mount_attr attr = {
81 .attr_set = tc->mount_attrs,
82 };
83 struct statvfs buf;
84
85 TST_EXP_FD_SILENT(open_tree(AT_FDCWD, MNTPOINT, AT_EMPTY_PATH |
86 AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE));
87 if (!TST_PASS)
88 return;
89
90 otfd = (int)TST_RET;
91
92 TST_EXP_PASS_SILENT(mount_setattr(otfd, "", AT_EMPTY_PATH, &attr, sizeof(attr)),
93 "%s set", tc->name);
94 if (!TST_PASS)
95 goto out1;
96
97 TST_EXP_PASS_SILENT(move_mount(otfd, "", AT_FDCWD, OT_MNTPOINT, MOVE_MOUNT_F_EMPTY_PATH));
98 if (!TST_PASS)
99 goto out1;
100 mount_flag = 1;
101 SAFE_CLOSE(otfd);
102
103 TST_EXP_PASS_SILENT(statvfs(OT_MNTPOINT, &buf), "statvfs sucess");
104 if (!TST_PASS)
105 goto out2;
106
107 if (buf.f_flag & tc->expect_attrs)
108 tst_res(TPASS, "%s is actually set as expected", tc->name);
109 else
110 tst_res(TFAIL, "%s is not actually set as expected", tc->name);
111
112 goto out2;
113
114 out1:
115 SAFE_CLOSE(otfd);
116 out2:
117 if (mount_flag)
118 SAFE_UMOUNT(OT_MNTPOINT);
119
120 mount_flag = 0;
121 }
122
123 static struct tst_test test = {
124 .tcnt = ARRAY_SIZE(tcases),
125 .test = run,
126 .setup = setup,
127 .cleanup = cleanup,
128 .needs_root = 1,
129 .mount_device = 1,
130 .mntpoint = MNTPOINT,
131 .all_filesystems = 1,
132 .skip_filesystems = (const char *const []){"fuse", NULL},
133 };
134