aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2014-08-22 17:39:03 -0400
committerEric W. Biederman <ebiederm@xmission.com>2014-12-02 11:46:48 -0500
commit4a44a19b470a886997d6647a77bb3e38dcbfa8c5 (patch)
tree33ca998ebb8ddf4071eca23a2bb0a9472606ada0
parent3e1866410f11356a9fd869beb3e95983dc79c067 (diff)
mnt: Update unprivileged remount test
- MNT_NODEV should be irrelevant except when reading back mount flags, no longer specify MNT_NODEV on remount. - Test MNT_NODEV on devpts where it is meaningful even for unprivileged mounts. - Add a test to verify that remount of a prexisting mount with the same flags is allowed and does not change those flags. - Cleanup up the definitions of MS_REC, MS_RELATIME, MS_STRICTATIME that are used when the code is built in an environment without them. - Correct the test error messages when tests fail. There were not 5 tests that tested MS_RELATIME. Cc: stable@vger.kernel.org Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--tools/testing/selftests/mount/unprivileged-remount-test.c172
1 files changed, 142 insertions, 30 deletions
diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c
index 1b3ff2fda4d0..9669d375625a 100644
--- a/tools/testing/selftests/mount/unprivileged-remount-test.c
+++ b/tools/testing/selftests/mount/unprivileged-remount-test.c
@@ -6,6 +6,8 @@
6#include <sys/types.h> 6#include <sys/types.h>
7#include <sys/mount.h> 7#include <sys/mount.h>
8#include <sys/wait.h> 8#include <sys/wait.h>
9#include <sys/vfs.h>
10#include <sys/statvfs.h>
9#include <stdlib.h> 11#include <stdlib.h>
10#include <unistd.h> 12#include <unistd.h>
11#include <fcntl.h> 13#include <fcntl.h>
@@ -32,11 +34,14 @@
32# define CLONE_NEWPID 0x20000000 34# define CLONE_NEWPID 0x20000000
33#endif 35#endif
34 36
37#ifndef MS_REC
38# define MS_REC 16384
39#endif
35#ifndef MS_RELATIME 40#ifndef MS_RELATIME
36#define MS_RELATIME (1 << 21) 41# define MS_RELATIME (1 << 21)
37#endif 42#endif
38#ifndef MS_STRICTATIME 43#ifndef MS_STRICTATIME
39#define MS_STRICTATIME (1 << 24) 44# define MS_STRICTATIME (1 << 24)
40#endif 45#endif
41 46
42static void die(char *fmt, ...) 47static void die(char *fmt, ...)
@@ -87,6 +92,45 @@ static void write_file(char *filename, char *fmt, ...)
87 } 92 }
88} 93}
89 94
95static int read_mnt_flags(const char *path)
96{
97 int ret;
98 struct statvfs stat;
99 int mnt_flags;
100
101 ret = statvfs(path, &stat);
102 if (ret != 0) {
103 die("statvfs of %s failed: %s\n",
104 path, strerror(errno));
105 }
106 if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | \
107 ST_NOEXEC | ST_NOATIME | ST_NODIRATIME | ST_RELATIME | \
108 ST_SYNCHRONOUS | ST_MANDLOCK)) {
109 die("Unrecognized mount flags\n");
110 }
111 mnt_flags = 0;
112 if (stat.f_flag & ST_RDONLY)
113 mnt_flags |= MS_RDONLY;
114 if (stat.f_flag & ST_NOSUID)
115 mnt_flags |= MS_NOSUID;
116 if (stat.f_flag & ST_NODEV)
117 mnt_flags |= MS_NODEV;
118 if (stat.f_flag & ST_NOEXEC)
119 mnt_flags |= MS_NOEXEC;
120 if (stat.f_flag & ST_NOATIME)
121 mnt_flags |= MS_NOATIME;
122 if (stat.f_flag & ST_NODIRATIME)
123 mnt_flags |= MS_NODIRATIME;
124 if (stat.f_flag & ST_RELATIME)
125 mnt_flags |= MS_RELATIME;
126 if (stat.f_flag & ST_SYNCHRONOUS)
127 mnt_flags |= MS_SYNCHRONOUS;
128 if (stat.f_flag & ST_MANDLOCK)
129 mnt_flags |= ST_MANDLOCK;
130
131 return mnt_flags;
132}
133
90static void create_and_enter_userns(void) 134static void create_and_enter_userns(void)
91{ 135{
92 uid_t uid; 136 uid_t uid;
@@ -118,7 +162,8 @@ static void create_and_enter_userns(void)
118} 162}
119 163
120static 164static
121bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags) 165bool test_unpriv_remount(const char *fstype, const char *mount_options,
166 int mount_flags, int remount_flags, int invalid_flags)
122{ 167{
123 pid_t child; 168 pid_t child;
124 169
@@ -151,9 +196,11 @@ bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags)
151 strerror(errno)); 196 strerror(errno));
152 } 197 }
153 198
154 if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) { 199 if (mount("testing", "/tmp", fstype, mount_flags, mount_options) != 0) {
155 die("mount of /tmp failed: %s\n", 200 die("mount of %s with options '%s' on /tmp failed: %s\n",
156 strerror(errno)); 201 fstype,
202 mount_options? mount_options : "",
203 strerror(errno));
157 } 204 }
158 205
159 create_and_enter_userns(); 206 create_and_enter_userns();
@@ -181,62 +228,127 @@ bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags)
181 228
182static bool test_unpriv_remount_simple(int mount_flags) 229static bool test_unpriv_remount_simple(int mount_flags)
183{ 230{
184 return test_unpriv_remount(mount_flags, mount_flags, 0); 231 return test_unpriv_remount("ramfs", NULL, mount_flags, mount_flags, 0);
185} 232}
186 233
187static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags) 234static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags)
188{ 235{
189 return test_unpriv_remount(mount_flags, mount_flags, invalid_flags); 236 return test_unpriv_remount("ramfs", NULL, mount_flags, mount_flags,
237 invalid_flags);
238}
239
240static bool test_priv_mount_unpriv_remount(void)
241{
242 pid_t child;
243 int ret;
244 const char *orig_path = "/dev";
245 const char *dest_path = "/tmp";
246 int orig_mnt_flags, remount_mnt_flags;
247
248 child = fork();
249 if (child == -1) {
250 die("fork failed: %s\n",
251 strerror(errno));
252 }
253 if (child != 0) { /* parent */
254 pid_t pid;
255 int status;
256 pid = waitpid(child, &status, 0);
257 if (pid == -1) {
258 die("waitpid failed: %s\n",
259 strerror(errno));
260 }
261 if (pid != child) {
262 die("waited for %d got %d\n",
263 child, pid);
264 }
265 if (!WIFEXITED(status)) {
266 die("child did not terminate cleanly\n");
267 }
268 return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false;
269 }
270
271 orig_mnt_flags = read_mnt_flags(orig_path);
272
273 create_and_enter_userns();
274 ret = unshare(CLONE_NEWNS);
275 if (ret != 0) {
276 die("unshare(CLONE_NEWNS) failed: %s\n",
277 strerror(errno));
278 }
279
280 ret = mount(orig_path, dest_path, "bind", MS_BIND | MS_REC, NULL);
281 if (ret != 0) {
282 die("recursive bind mount of %s onto %s failed: %s\n",
283 orig_path, dest_path, strerror(errno));
284 }
285
286 ret = mount(dest_path, dest_path, "none",
287 MS_REMOUNT | MS_BIND | orig_mnt_flags , NULL);
288 if (ret != 0) {
289 /* system("cat /proc/self/mounts"); */
290 die("remount of /tmp failed: %s\n",
291 strerror(errno));
292 }
293
294 remount_mnt_flags = read_mnt_flags(dest_path);
295 if (orig_mnt_flags != remount_mnt_flags) {
296 die("Mount flags unexpectedly changed during remount of %s originally mounted on %s\n",
297 dest_path, orig_path);
298 }
299 exit(EXIT_SUCCESS);
190} 300}
191 301
192int main(int argc, char **argv) 302int main(int argc, char **argv)
193{ 303{
194 if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) { 304 if (!test_unpriv_remount_simple(MS_RDONLY)) {
195 die("MS_RDONLY malfunctions\n"); 305 die("MS_RDONLY malfunctions\n");
196 } 306 }
197 if (!test_unpriv_remount_simple(MS_NODEV)) { 307 if (!test_unpriv_remount("devpts", "newinstance", MS_NODEV, MS_NODEV, 0)) {
198 die("MS_NODEV malfunctions\n"); 308 die("MS_NODEV malfunctions\n");
199 } 309 }
200 if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) { 310 if (!test_unpriv_remount_simple(MS_NOSUID)) {
201 die("MS_NOSUID malfunctions\n"); 311 die("MS_NOSUID malfunctions\n");
202 } 312 }
203 if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) { 313 if (!test_unpriv_remount_simple(MS_NOEXEC)) {
204 die("MS_NOEXEC malfunctions\n"); 314 die("MS_NOEXEC malfunctions\n");
205 } 315 }
206 if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV, 316 if (!test_unpriv_remount_atime(MS_RELATIME,
207 MS_NOATIME|MS_NODEV)) 317 MS_NOATIME))
208 { 318 {
209 die("MS_RELATIME malfunctions\n"); 319 die("MS_RELATIME malfunctions\n");
210 } 320 }
211 if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV, 321 if (!test_unpriv_remount_atime(MS_STRICTATIME,
212 MS_NOATIME|MS_NODEV)) 322 MS_NOATIME))
213 { 323 {
214 die("MS_STRICTATIME malfunctions\n"); 324 die("MS_STRICTATIME malfunctions\n");
215 } 325 }
216 if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV, 326 if (!test_unpriv_remount_atime(MS_NOATIME,
217 MS_STRICTATIME|MS_NODEV)) 327 MS_STRICTATIME))
218 { 328 {
219 die("MS_RELATIME malfunctions\n"); 329 die("MS_NOATIME malfunctions\n");
220 } 330 }
221 if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV, 331 if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME,
222 MS_NOATIME|MS_NODEV)) 332 MS_NOATIME))
223 { 333 {
224 die("MS_RELATIME malfunctions\n"); 334 die("MS_RELATIME|MS_NODIRATIME malfunctions\n");
225 } 335 }
226 if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV, 336 if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME,
227 MS_NOATIME|MS_NODEV)) 337 MS_NOATIME))
228 { 338 {
229 die("MS_RELATIME malfunctions\n"); 339 die("MS_STRICTATIME|MS_NODIRATIME malfunctions\n");
230 } 340 }
231 if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV, 341 if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME,
232 MS_STRICTATIME|MS_NODEV)) 342 MS_STRICTATIME))
233 { 343 {
234 die("MS_RELATIME malfunctions\n"); 344 die("MS_NOATIME|MS_DIRATIME malfunctions\n");
235 } 345 }
236 if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV, 346 if (!test_unpriv_remount("ramfs", NULL, MS_STRICTATIME, 0, MS_NOATIME))
237 MS_NOATIME|MS_NODEV))
238 { 347 {
239 die("Default atime malfunctions\n"); 348 die("Default atime malfunctions\n");
240 } 349 }
350 if (!test_priv_mount_unpriv_remount()) {
351 die("Mount flags unexpectedly changed after remount\n");
352 }
241 return EXIT_SUCCESS; 353 return EXIT_SUCCESS;
242} 354}