1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <sched.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <pthread.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <sys/mount.h>
11 #include <sys/wait.h>
12 #include <sys/vfs.h>
13 #include <sys/statvfs.h>
14 #include <sys/sysinfo.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <grp.h>
19 #include <stdbool.h>
20 #include <stdarg.h>
21 
22 #include "../kselftest_harness.h"
23 
24 #ifndef CLONE_NEWNS
25 #define CLONE_NEWNS 0x00020000
26 #endif
27 
28 #ifndef CLONE_NEWUSER
29 #define CLONE_NEWUSER 0x10000000
30 #endif
31 
32 #ifndef MS_REC
33 #define MS_REC 16384
34 #endif
35 
36 #ifndef MS_RELATIME
37 #define MS_RELATIME (1 << 21)
38 #endif
39 
40 #ifndef MS_STRICTATIME
41 #define MS_STRICTATIME (1 << 24)
42 #endif
43 
44 #ifndef MOUNT_ATTR_RDONLY
45 #define MOUNT_ATTR_RDONLY 0x00000001
46 #endif
47 
48 #ifndef MOUNT_ATTR_NOSUID
49 #define MOUNT_ATTR_NOSUID 0x00000002
50 #endif
51 
52 #ifndef MOUNT_ATTR_NOEXEC
53 #define MOUNT_ATTR_NOEXEC 0x00000008
54 #endif
55 
56 #ifndef MOUNT_ATTR_NODIRATIME
57 #define MOUNT_ATTR_NODIRATIME 0x00000080
58 #endif
59 
60 #ifndef MOUNT_ATTR__ATIME
61 #define MOUNT_ATTR__ATIME 0x00000070
62 #endif
63 
64 #ifndef MOUNT_ATTR_RELATIME
65 #define MOUNT_ATTR_RELATIME 0x00000000
66 #endif
67 
68 #ifndef MOUNT_ATTR_NOATIME
69 #define MOUNT_ATTR_NOATIME 0x00000010
70 #endif
71 
72 #ifndef MOUNT_ATTR_STRICTATIME
73 #define MOUNT_ATTR_STRICTATIME 0x00000020
74 #endif
75 
76 #ifndef AT_RECURSIVE
77 #define AT_RECURSIVE 0x8000
78 #endif
79 
80 #ifndef MS_SHARED
81 #define MS_SHARED (1 << 20)
82 #endif
83 
84 #define DEFAULT_THREADS 4
85 #define ptr_to_int(p) ((int)((intptr_t)(p)))
86 #define int_to_ptr(u) ((void *)((intptr_t)(u)))
87 
88 #ifndef __NR_mount_setattr
89 	#if defined __alpha__
90 		#define __NR_mount_setattr 552
91 	#elif defined _MIPS_SIM
92 		#if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
93 			#define __NR_mount_setattr (442 + 4000)
94 		#endif
95 		#if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
96 			#define __NR_mount_setattr (442 + 6000)
97 		#endif
98 		#if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
99 			#define __NR_mount_setattr (442 + 5000)
100 		#endif
101 	#elif defined __ia64__
102 		#define __NR_mount_setattr (442 + 1024)
103 	#else
104 		#define __NR_mount_setattr 442
105 	#endif
106 
107 struct mount_attr {
108 	__u64 attr_set;
109 	__u64 attr_clr;
110 	__u64 propagation;
111 	__u64 userns_fd;
112 };
113 #endif
114 
115 #ifndef __NR_open_tree
116 	#if defined __alpha__
117 		#define __NR_open_tree 538
118 	#elif defined _MIPS_SIM
119 		#if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
120 			#define __NR_open_tree 4428
121 		#endif
122 		#if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
123 			#define __NR_open_tree 6428
124 		#endif
125 		#if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
126 			#define __NR_open_tree 5428
127 		#endif
128 	#elif defined __ia64__
129 		#define __NR_open_tree (428 + 1024)
130 	#else
131 		#define __NR_open_tree 428
132 	#endif
133 #endif
134 
135 #ifndef MOUNT_ATTR_IDMAP
136 #define MOUNT_ATTR_IDMAP 0x00100000
137 #endif
138 
139 #ifndef MOUNT_ATTR_NOSYMFOLLOW
140 #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
141 #endif
142 
sys_mount_setattr(int dfd,const char * path,unsigned int flags,struct mount_attr * attr,size_t size)143 static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags,
144 				    struct mount_attr *attr, size_t size)
145 {
146 	return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
147 }
148 
149 #ifndef OPEN_TREE_CLONE
150 #define OPEN_TREE_CLONE 1
151 #endif
152 
153 #ifndef OPEN_TREE_CLOEXEC
154 #define OPEN_TREE_CLOEXEC O_CLOEXEC
155 #endif
156 
157 #ifndef AT_RECURSIVE
158 #define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
159 #endif
160 
sys_open_tree(int dfd,const char * filename,unsigned int flags)161 static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags)
162 {
163 	return syscall(__NR_open_tree, dfd, filename, flags);
164 }
165 
write_nointr(int fd,const void * buf,size_t count)166 static ssize_t write_nointr(int fd, const void *buf, size_t count)
167 {
168 	ssize_t ret;
169 
170 	do {
171 		ret = write(fd, buf, count);
172 	} while (ret < 0 && errno == EINTR);
173 
174 	return ret;
175 }
176 
write_file(const char * path,const void * buf,size_t count)177 static int write_file(const char *path, const void *buf, size_t count)
178 {
179 	int fd;
180 	ssize_t ret;
181 
182 	fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
183 	if (fd < 0)
184 		return -1;
185 
186 	ret = write_nointr(fd, buf, count);
187 	close(fd);
188 	if (ret < 0 || (size_t)ret != count)
189 		return -1;
190 
191 	return 0;
192 }
193 
create_and_enter_userns(void)194 static int create_and_enter_userns(void)
195 {
196 	uid_t uid;
197 	gid_t gid;
198 	char map[100];
199 
200 	uid = getuid();
201 	gid = getgid();
202 
203 	if (unshare(CLONE_NEWUSER))
204 		return -1;
205 
206 	if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) &&
207 	    errno != ENOENT)
208 		return -1;
209 
210 	snprintf(map, sizeof(map), "0 %d 1", uid);
211 	if (write_file("/proc/self/uid_map", map, strlen(map)))
212 		return -1;
213 
214 
215 	snprintf(map, sizeof(map), "0 %d 1", gid);
216 	if (write_file("/proc/self/gid_map", map, strlen(map)))
217 		return -1;
218 
219 	if (setgid(0))
220 		return -1;
221 
222 	if (setuid(0))
223 		return -1;
224 
225 	return 0;
226 }
227 
prepare_unpriv_mountns(void)228 static int prepare_unpriv_mountns(void)
229 {
230 	if (create_and_enter_userns())
231 		return -1;
232 
233 	if (unshare(CLONE_NEWNS))
234 		return -1;
235 
236 	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
237 		return -1;
238 
239 	return 0;
240 }
241 
242 #ifndef ST_NOSYMFOLLOW
243 #define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */
244 #endif
245 
read_mnt_flags(const char * path)246 static int read_mnt_flags(const char *path)
247 {
248 	int ret;
249 	struct statvfs stat;
250 	unsigned int mnt_flags;
251 
252 	ret = statvfs(path, &stat);
253 	if (ret != 0)
254 		return -EINVAL;
255 
256 	if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC |
257 			    ST_NOATIME | ST_NODIRATIME | ST_RELATIME |
258 			    ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW))
259 		return -EINVAL;
260 
261 	mnt_flags = 0;
262 	if (stat.f_flag & ST_RDONLY)
263 		mnt_flags |= MS_RDONLY;
264 	if (stat.f_flag & ST_NOSUID)
265 		mnt_flags |= MS_NOSUID;
266 	if (stat.f_flag & ST_NODEV)
267 		mnt_flags |= MS_NODEV;
268 	if (stat.f_flag & ST_NOEXEC)
269 		mnt_flags |= MS_NOEXEC;
270 	if (stat.f_flag & ST_NOATIME)
271 		mnt_flags |= MS_NOATIME;
272 	if (stat.f_flag & ST_NODIRATIME)
273 		mnt_flags |= MS_NODIRATIME;
274 	if (stat.f_flag & ST_RELATIME)
275 		mnt_flags |= MS_RELATIME;
276 	if (stat.f_flag & ST_SYNCHRONOUS)
277 		mnt_flags |= MS_SYNCHRONOUS;
278 	if (stat.f_flag & ST_MANDLOCK)
279 		mnt_flags |= ST_MANDLOCK;
280 	if (stat.f_flag & ST_NOSYMFOLLOW)
281 		mnt_flags |= ST_NOSYMFOLLOW;
282 
283 	return mnt_flags;
284 }
285 
get_field(char * src,int nfields)286 static char *get_field(char *src, int nfields)
287 {
288 	int i;
289 	char *p = src;
290 
291 	for (i = 0; i < nfields; i++) {
292 		while (*p && *p != ' ' && *p != '\t')
293 			p++;
294 
295 		if (!*p)
296 			break;
297 
298 		p++;
299 	}
300 
301 	return p;
302 }
303 
null_endofword(char * word)304 static void null_endofword(char *word)
305 {
306 	while (*word && *word != ' ' && *word != '\t')
307 		word++;
308 	*word = '\0';
309 }
310 
is_shared_mount(const char * path)311 static bool is_shared_mount(const char *path)
312 {
313 	size_t len = 0;
314 	char *line = NULL;
315 	FILE *f = NULL;
316 
317 	f = fopen("/proc/self/mountinfo", "re");
318 	if (!f)
319 		return false;
320 
321 	while (getline(&line, &len, f) != -1) {
322 		char *opts, *target;
323 
324 		target = get_field(line, 4);
325 		if (!target)
326 			continue;
327 
328 		opts = get_field(target, 2);
329 		if (!opts)
330 			continue;
331 
332 		null_endofword(target);
333 
334 		if (strcmp(target, path) != 0)
335 			continue;
336 
337 		null_endofword(opts);
338 		if (strstr(opts, "shared:"))
339 			return true;
340 	}
341 
342 	free(line);
343 	fclose(f);
344 
345 	return false;
346 }
347 
mount_setattr_thread(void * data)348 static void *mount_setattr_thread(void *data)
349 {
350 	struct mount_attr attr = {
351 		.attr_set	= MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID,
352 		.attr_clr	= 0,
353 		.propagation	= MS_SHARED,
354 	};
355 
356 	if (sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)))
357 		pthread_exit(int_to_ptr(-1));
358 
359 	pthread_exit(int_to_ptr(0));
360 }
361 
362 /* Attempt to de-conflict with the selftests tree. */
363 #ifndef SKIP
364 #define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
365 #endif
366 
mount_setattr_supported(void)367 static bool mount_setattr_supported(void)
368 {
369 	int ret;
370 
371 	ret = sys_mount_setattr(-EBADF, "", AT_EMPTY_PATH, NULL, 0);
372 	if (ret < 0 && errno == ENOSYS)
373 		return false;
374 
375 	return true;
376 }
377 
FIXTURE(mount_setattr)378 FIXTURE(mount_setattr) {
379 };
380 
381 #define NOSYMFOLLOW_TARGET "/mnt/A/AA/data"
382 #define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink"
383 
FIXTURE_SETUP(mount_setattr)384 FIXTURE_SETUP(mount_setattr)
385 {
386 	int fd = -EBADF;
387 
388 	if (!mount_setattr_supported())
389 		SKIP(return, "mount_setattr syscall not supported");
390 
391 	ASSERT_EQ(prepare_unpriv_mountns(), 0);
392 
393 	(void)umount2("/mnt", MNT_DETACH);
394 	(void)umount2("/tmp", MNT_DETACH);
395 
396 	ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV,
397 			"size=100000,mode=700"), 0);
398 
399 	ASSERT_EQ(mkdir("/tmp/B", 0777), 0);
400 
401 	ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV,
402 			"size=100000,mode=700"), 0);
403 
404 	ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0);
405 
406 	ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV,
407 			"size=100000,mode=700"), 0);
408 
409 	ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
410 			"size=100000,mode=700"), 0);
411 
412 	ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
413 
414 	ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV,
415 			"size=100000,mode=700"), 0);
416 
417 	ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
418 
419 	ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
420 
421 	ASSERT_EQ(mkdir("/mnt/B", 0777), 0);
422 
423 	ASSERT_EQ(mount("testing", "/mnt/B", "ramfs",
424 			MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0);
425 
426 	ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0);
427 
428 	ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
429 			MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
430 
431 	fd = creat(NOSYMFOLLOW_TARGET, O_RDWR | O_CLOEXEC);
432 	ASSERT_GT(fd, 0);
433 	ASSERT_EQ(symlink(NOSYMFOLLOW_TARGET, NOSYMFOLLOW_SYMLINK), 0);
434 	ASSERT_EQ(close(fd), 0);
435 }
436 
FIXTURE_TEARDOWN(mount_setattr)437 FIXTURE_TEARDOWN(mount_setattr)
438 {
439 	if (!mount_setattr_supported())
440 		SKIP(return, "mount_setattr syscall not supported");
441 
442 	(void)umount2("/mnt/A", MNT_DETACH);
443 	(void)umount2("/tmp", MNT_DETACH);
444 }
445 
TEST_F(mount_setattr,invalid_attributes)446 TEST_F(mount_setattr, invalid_attributes)
447 {
448 	struct mount_attr invalid_attr = {
449 		.attr_set = (1U << 31),
450 	};
451 
452 	if (!mount_setattr_supported())
453 		SKIP(return, "mount_setattr syscall not supported");
454 
455 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
456 				    sizeof(invalid_attr)), 0);
457 
458 	invalid_attr.attr_set	= 0;
459 	invalid_attr.attr_clr	= (1U << 31);
460 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
461 				    sizeof(invalid_attr)), 0);
462 
463 	invalid_attr.attr_clr		= 0;
464 	invalid_attr.propagation	= (1U << 31);
465 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
466 				    sizeof(invalid_attr)), 0);
467 
468 	invalid_attr.attr_set		= (1U << 31);
469 	invalid_attr.attr_clr		= (1U << 31);
470 	invalid_attr.propagation	= (1U << 31);
471 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
472 				    sizeof(invalid_attr)), 0);
473 
474 	ASSERT_NE(sys_mount_setattr(-1, "mnt/A", AT_RECURSIVE, &invalid_attr,
475 				    sizeof(invalid_attr)), 0);
476 }
477 
TEST_F(mount_setattr,extensibility)478 TEST_F(mount_setattr, extensibility)
479 {
480 	unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
481 	char *s = "dummy";
482 	struct mount_attr invalid_attr = {};
483 	struct mount_attr_large {
484 		struct mount_attr attr1;
485 		struct mount_attr attr2;
486 		struct mount_attr attr3;
487 	} large_attr = {};
488 
489 	if (!mount_setattr_supported())
490 		SKIP(return, "mount_setattr syscall not supported");
491 
492 	old_flags = read_mnt_flags("/mnt/A");
493 	ASSERT_GT(old_flags, 0);
494 
495 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, NULL,
496 				    sizeof(invalid_attr)), 0);
497 	ASSERT_EQ(errno, EFAULT);
498 
499 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, (void *)s,
500 				    sizeof(invalid_attr)), 0);
501 	ASSERT_EQ(errno, EINVAL);
502 
503 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 0), 0);
504 	ASSERT_EQ(errno, EINVAL);
505 
506 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
507 				    sizeof(invalid_attr) / 2), 0);
508 	ASSERT_EQ(errno, EINVAL);
509 
510 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
511 				    sizeof(invalid_attr) / 2), 0);
512 	ASSERT_EQ(errno, EINVAL);
513 
514 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
515 				    (void *)&large_attr, sizeof(large_attr)), 0);
516 
517 	large_attr.attr3.attr_set = MOUNT_ATTR_RDONLY;
518 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
519 				    (void *)&large_attr, sizeof(large_attr)), 0);
520 
521 	large_attr.attr3.attr_set = 0;
522 	large_attr.attr1.attr_set = MOUNT_ATTR_RDONLY;
523 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
524 				    (void *)&large_attr, sizeof(large_attr)), 0);
525 
526 	expected_flags = old_flags;
527 	expected_flags |= MS_RDONLY;
528 
529 	new_flags = read_mnt_flags("/mnt/A");
530 	ASSERT_EQ(new_flags, expected_flags);
531 
532 	new_flags = read_mnt_flags("/mnt/A/AA");
533 	ASSERT_EQ(new_flags, expected_flags);
534 
535 	new_flags = read_mnt_flags("/mnt/A/AA/B");
536 	ASSERT_EQ(new_flags, expected_flags);
537 
538 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
539 	ASSERT_EQ(new_flags, expected_flags);
540 }
541 
TEST_F(mount_setattr,basic)542 TEST_F(mount_setattr, basic)
543 {
544 	unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
545 	struct mount_attr attr = {
546 		.attr_set	= MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
547 		.attr_clr	= MOUNT_ATTR__ATIME,
548 	};
549 
550 	if (!mount_setattr_supported())
551 		SKIP(return, "mount_setattr syscall not supported");
552 
553 	old_flags = read_mnt_flags("/mnt/A");
554 	ASSERT_GT(old_flags, 0);
555 
556 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", 0, &attr, sizeof(attr)), 0);
557 
558 	expected_flags = old_flags;
559 	expected_flags |= MS_RDONLY;
560 	expected_flags |= MS_NOEXEC;
561 	expected_flags &= ~MS_NOATIME;
562 	expected_flags |= MS_RELATIME;
563 
564 	new_flags = read_mnt_flags("/mnt/A");
565 	ASSERT_EQ(new_flags, expected_flags);
566 
567 	new_flags = read_mnt_flags("/mnt/A/AA");
568 	ASSERT_EQ(new_flags, old_flags);
569 
570 	new_flags = read_mnt_flags("/mnt/A/AA/B");
571 	ASSERT_EQ(new_flags, old_flags);
572 
573 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
574 	ASSERT_EQ(new_flags, old_flags);
575 }
576 
TEST_F(mount_setattr,basic_recursive)577 TEST_F(mount_setattr, basic_recursive)
578 {
579 	int fd;
580 	unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
581 	struct mount_attr attr = {
582 		.attr_set	= MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
583 		.attr_clr	= MOUNT_ATTR__ATIME,
584 	};
585 
586 	if (!mount_setattr_supported())
587 		SKIP(return, "mount_setattr syscall not supported");
588 
589 	old_flags = read_mnt_flags("/mnt/A");
590 	ASSERT_GT(old_flags, 0);
591 
592 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
593 
594 	expected_flags = old_flags;
595 	expected_flags |= MS_RDONLY;
596 	expected_flags |= MS_NOEXEC;
597 	expected_flags &= ~MS_NOATIME;
598 	expected_flags |= MS_RELATIME;
599 
600 	new_flags = read_mnt_flags("/mnt/A");
601 	ASSERT_EQ(new_flags, expected_flags);
602 
603 	new_flags = read_mnt_flags("/mnt/A/AA");
604 	ASSERT_EQ(new_flags, expected_flags);
605 
606 	new_flags = read_mnt_flags("/mnt/A/AA/B");
607 	ASSERT_EQ(new_flags, expected_flags);
608 
609 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
610 	ASSERT_EQ(new_flags, expected_flags);
611 
612 	memset(&attr, 0, sizeof(attr));
613 	attr.attr_clr = MOUNT_ATTR_RDONLY;
614 	attr.propagation = MS_SHARED;
615 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
616 
617 	expected_flags &= ~MS_RDONLY;
618 	new_flags = read_mnt_flags("/mnt/A");
619 	ASSERT_EQ(new_flags, expected_flags);
620 
621 	ASSERT_EQ(is_shared_mount("/mnt/A"), true);
622 
623 	new_flags = read_mnt_flags("/mnt/A/AA");
624 	ASSERT_EQ(new_flags, expected_flags);
625 
626 	ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
627 
628 	new_flags = read_mnt_flags("/mnt/A/AA/B");
629 	ASSERT_EQ(new_flags, expected_flags);
630 
631 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
632 
633 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
634 	ASSERT_EQ(new_flags, expected_flags);
635 
636 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
637 
638 	fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777);
639 	ASSERT_GE(fd, 0);
640 
641 	/*
642 	 * We're holding a fd open for writing so this needs to fail somewhere
643 	 * in the middle and the mount options need to be unchanged.
644 	 */
645 	attr.attr_set = MOUNT_ATTR_RDONLY;
646 	ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
647 
648 	new_flags = read_mnt_flags("/mnt/A");
649 	ASSERT_EQ(new_flags, expected_flags);
650 
651 	ASSERT_EQ(is_shared_mount("/mnt/A"), true);
652 
653 	new_flags = read_mnt_flags("/mnt/A/AA");
654 	ASSERT_EQ(new_flags, expected_flags);
655 
656 	ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
657 
658 	new_flags = read_mnt_flags("/mnt/A/AA/B");
659 	ASSERT_EQ(new_flags, expected_flags);
660 
661 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
662 
663 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
664 	ASSERT_EQ(new_flags, expected_flags);
665 
666 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
667 
668 	EXPECT_EQ(close(fd), 0);
669 }
670 
TEST_F(mount_setattr,mount_has_writers)671 TEST_F(mount_setattr, mount_has_writers)
672 {
673 	int fd, dfd;
674 	unsigned int old_flags = 0, new_flags = 0;
675 	struct mount_attr attr = {
676 		.attr_set	= MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
677 		.attr_clr	= MOUNT_ATTR__ATIME,
678 		.propagation	= MS_SHARED,
679 	};
680 
681 	if (!mount_setattr_supported())
682 		SKIP(return, "mount_setattr syscall not supported");
683 
684 	old_flags = read_mnt_flags("/mnt/A");
685 	ASSERT_GT(old_flags, 0);
686 
687 	fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777);
688 	ASSERT_GE(fd, 0);
689 
690 	/*
691 	 * We're holding a fd open to a mount somwhere in the middle so this
692 	 * needs to fail somewhere in the middle. After this the mount options
693 	 * need to be unchanged.
694 	 */
695 	ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
696 
697 	new_flags = read_mnt_flags("/mnt/A");
698 	ASSERT_EQ(new_flags, old_flags);
699 
700 	ASSERT_EQ(is_shared_mount("/mnt/A"), false);
701 
702 	new_flags = read_mnt_flags("/mnt/A/AA");
703 	ASSERT_EQ(new_flags, old_flags);
704 
705 	ASSERT_EQ(is_shared_mount("/mnt/A/AA"), false);
706 
707 	new_flags = read_mnt_flags("/mnt/A/AA/B");
708 	ASSERT_EQ(new_flags, old_flags);
709 
710 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), false);
711 
712 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
713 	ASSERT_EQ(new_flags, old_flags);
714 
715 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), false);
716 
717 	dfd = open("/mnt/A/AA/B", O_DIRECTORY | O_CLOEXEC);
718 	ASSERT_GE(dfd, 0);
719 	EXPECT_EQ(fsync(dfd), 0);
720 	EXPECT_EQ(close(dfd), 0);
721 
722 	EXPECT_EQ(fsync(fd), 0);
723 	EXPECT_EQ(close(fd), 0);
724 
725 	/* All writers are gone so this should succeed. */
726 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
727 }
728 
TEST_F(mount_setattr,mixed_mount_options)729 TEST_F(mount_setattr, mixed_mount_options)
730 {
731 	unsigned int old_flags1 = 0, old_flags2 = 0, new_flags = 0, expected_flags = 0;
732 	struct mount_attr attr = {
733 		.attr_clr = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME,
734 		.attr_set = MOUNT_ATTR_RELATIME,
735 	};
736 
737 	if (!mount_setattr_supported())
738 		SKIP(return, "mount_setattr syscall not supported");
739 
740 	old_flags1 = read_mnt_flags("/mnt/B");
741 	ASSERT_GT(old_flags1, 0);
742 
743 	old_flags2 = read_mnt_flags("/mnt/B/BB");
744 	ASSERT_GT(old_flags2, 0);
745 
746 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/B", AT_RECURSIVE, &attr, sizeof(attr)), 0);
747 
748 	expected_flags = old_flags2;
749 	expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID);
750 	expected_flags |= MS_RELATIME;
751 
752 	new_flags = read_mnt_flags("/mnt/B");
753 	ASSERT_EQ(new_flags, expected_flags);
754 
755 	expected_flags = old_flags2;
756 	expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID);
757 	expected_flags |= MS_RELATIME;
758 
759 	new_flags = read_mnt_flags("/mnt/B/BB");
760 	ASSERT_EQ(new_flags, expected_flags);
761 }
762 
TEST_F(mount_setattr,time_changes)763 TEST_F(mount_setattr, time_changes)
764 {
765 	unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
766 	struct mount_attr attr = {
767 		.attr_set	= MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME,
768 	};
769 
770 	if (!mount_setattr_supported())
771 		SKIP(return, "mount_setattr syscall not supported");
772 
773 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
774 
775 	attr.attr_set = MOUNT_ATTR_STRICTATIME;
776 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
777 
778 	attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME;
779 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
780 
781 	attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME;
782 	attr.attr_clr = MOUNT_ATTR__ATIME;
783 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
784 
785 	attr.attr_set = 0;
786 	attr.attr_clr = MOUNT_ATTR_STRICTATIME;
787 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
788 
789 	attr.attr_clr = MOUNT_ATTR_NOATIME;
790 	ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
791 
792 	old_flags = read_mnt_flags("/mnt/A");
793 	ASSERT_GT(old_flags, 0);
794 
795 	attr.attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME;
796 	attr.attr_clr = MOUNT_ATTR__ATIME;
797 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
798 
799 	expected_flags = old_flags;
800 	expected_flags |= MS_NOATIME;
801 	expected_flags |= MS_NODIRATIME;
802 
803 	new_flags = read_mnt_flags("/mnt/A");
804 	ASSERT_EQ(new_flags, expected_flags);
805 
806 	new_flags = read_mnt_flags("/mnt/A/AA");
807 	ASSERT_EQ(new_flags, expected_flags);
808 
809 	new_flags = read_mnt_flags("/mnt/A/AA/B");
810 	ASSERT_EQ(new_flags, expected_flags);
811 
812 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
813 	ASSERT_EQ(new_flags, expected_flags);
814 
815 	memset(&attr, 0, sizeof(attr));
816 	attr.attr_set &= ~MOUNT_ATTR_NOATIME;
817 	attr.attr_set |= MOUNT_ATTR_RELATIME;
818 	attr.attr_clr |= MOUNT_ATTR__ATIME;
819 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
820 
821 	expected_flags &= ~MS_NOATIME;
822 	expected_flags |= MS_RELATIME;
823 
824 	new_flags = read_mnt_flags("/mnt/A");
825 	ASSERT_EQ(new_flags, expected_flags);
826 
827 	new_flags = read_mnt_flags("/mnt/A/AA");
828 	ASSERT_EQ(new_flags, expected_flags);
829 
830 	new_flags = read_mnt_flags("/mnt/A/AA/B");
831 	ASSERT_EQ(new_flags, expected_flags);
832 
833 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
834 	ASSERT_EQ(new_flags, expected_flags);
835 
836 	memset(&attr, 0, sizeof(attr));
837 	attr.attr_set &= ~MOUNT_ATTR_RELATIME;
838 	attr.attr_set |= MOUNT_ATTR_STRICTATIME;
839 	attr.attr_clr |= MOUNT_ATTR__ATIME;
840 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
841 
842 	expected_flags &= ~MS_RELATIME;
843 
844 	new_flags = read_mnt_flags("/mnt/A");
845 	ASSERT_EQ(new_flags, expected_flags);
846 
847 	new_flags = read_mnt_flags("/mnt/A/AA");
848 	ASSERT_EQ(new_flags, expected_flags);
849 
850 	new_flags = read_mnt_flags("/mnt/A/AA/B");
851 	ASSERT_EQ(new_flags, expected_flags);
852 
853 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
854 	ASSERT_EQ(new_flags, expected_flags);
855 
856 	memset(&attr, 0, sizeof(attr));
857 	attr.attr_set &= ~MOUNT_ATTR_STRICTATIME;
858 	attr.attr_set |= MOUNT_ATTR_NOATIME;
859 	attr.attr_clr |= MOUNT_ATTR__ATIME;
860 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
861 
862 	expected_flags |= MS_NOATIME;
863 	new_flags = read_mnt_flags("/mnt/A");
864 	ASSERT_EQ(new_flags, expected_flags);
865 
866 	new_flags = read_mnt_flags("/mnt/A/AA");
867 	ASSERT_EQ(new_flags, expected_flags);
868 
869 	new_flags = read_mnt_flags("/mnt/A/AA/B");
870 	ASSERT_EQ(new_flags, expected_flags);
871 
872 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
873 	ASSERT_EQ(new_flags, expected_flags);
874 
875 	memset(&attr, 0, sizeof(attr));
876 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
877 
878 	new_flags = read_mnt_flags("/mnt/A");
879 	ASSERT_EQ(new_flags, expected_flags);
880 
881 	new_flags = read_mnt_flags("/mnt/A/AA");
882 	ASSERT_EQ(new_flags, expected_flags);
883 
884 	new_flags = read_mnt_flags("/mnt/A/AA/B");
885 	ASSERT_EQ(new_flags, expected_flags);
886 
887 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
888 	ASSERT_EQ(new_flags, expected_flags);
889 
890 	memset(&attr, 0, sizeof(attr));
891 	attr.attr_clr = MOUNT_ATTR_NODIRATIME;
892 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
893 
894 	expected_flags &= ~MS_NODIRATIME;
895 
896 	new_flags = read_mnt_flags("/mnt/A");
897 	ASSERT_EQ(new_flags, expected_flags);
898 
899 	new_flags = read_mnt_flags("/mnt/A/AA");
900 	ASSERT_EQ(new_flags, expected_flags);
901 
902 	new_flags = read_mnt_flags("/mnt/A/AA/B");
903 	ASSERT_EQ(new_flags, expected_flags);
904 
905 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
906 	ASSERT_EQ(new_flags, expected_flags);
907 }
908 
TEST_F(mount_setattr,multi_threaded)909 TEST_F(mount_setattr, multi_threaded)
910 {
911 	int i, j, nthreads, ret = 0;
912 	unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
913 	pthread_attr_t pattr;
914 	pthread_t threads[DEFAULT_THREADS];
915 
916 	if (!mount_setattr_supported())
917 		SKIP(return, "mount_setattr syscall not supported");
918 
919 	old_flags = read_mnt_flags("/mnt/A");
920 	ASSERT_GT(old_flags, 0);
921 
922 	/* Try to change mount options from multiple threads. */
923 	nthreads = get_nprocs_conf();
924 	if (nthreads > DEFAULT_THREADS)
925 		nthreads = DEFAULT_THREADS;
926 
927 	pthread_attr_init(&pattr);
928 	for (i = 0; i < nthreads; i++)
929 		ASSERT_EQ(pthread_create(&threads[i], &pattr, mount_setattr_thread, NULL), 0);
930 
931 	for (j = 0; j < i; j++) {
932 		void *retptr = NULL;
933 
934 		EXPECT_EQ(pthread_join(threads[j], &retptr), 0);
935 
936 		ret += ptr_to_int(retptr);
937 		EXPECT_EQ(ret, 0);
938 	}
939 	pthread_attr_destroy(&pattr);
940 
941 	ASSERT_EQ(ret, 0);
942 
943 	expected_flags = old_flags;
944 	expected_flags |= MS_RDONLY;
945 	expected_flags |= MS_NOSUID;
946 	new_flags = read_mnt_flags("/mnt/A");
947 	ASSERT_EQ(new_flags, expected_flags);
948 
949 	ASSERT_EQ(is_shared_mount("/mnt/A"), true);
950 
951 	new_flags = read_mnt_flags("/mnt/A/AA");
952 	ASSERT_EQ(new_flags, expected_flags);
953 
954 	ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
955 
956 	new_flags = read_mnt_flags("/mnt/A/AA/B");
957 	ASSERT_EQ(new_flags, expected_flags);
958 
959 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
960 
961 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
962 	ASSERT_EQ(new_flags, expected_flags);
963 
964 	ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
965 }
966 
TEST_F(mount_setattr,wrong_user_namespace)967 TEST_F(mount_setattr, wrong_user_namespace)
968 {
969 	int ret;
970 	struct mount_attr attr = {
971 		.attr_set = MOUNT_ATTR_RDONLY,
972 	};
973 
974 	if (!mount_setattr_supported())
975 		SKIP(return, "mount_setattr syscall not supported");
976 
977 	EXPECT_EQ(create_and_enter_userns(), 0);
978 	ret = sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr));
979 	ASSERT_LT(ret, 0);
980 	ASSERT_EQ(errno, EPERM);
981 }
982 
TEST_F(mount_setattr,wrong_mount_namespace)983 TEST_F(mount_setattr, wrong_mount_namespace)
984 {
985 	int fd, ret;
986 	struct mount_attr attr = {
987 		.attr_set = MOUNT_ATTR_RDONLY,
988 	};
989 
990 	if (!mount_setattr_supported())
991 		SKIP(return, "mount_setattr syscall not supported");
992 
993 	fd = open("/mnt/A", O_DIRECTORY | O_CLOEXEC);
994 	ASSERT_GE(fd, 0);
995 
996 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
997 
998 	ret = sys_mount_setattr(fd, "", AT_EMPTY_PATH | AT_RECURSIVE, &attr, sizeof(attr));
999 	ASSERT_LT(ret, 0);
1000 	ASSERT_EQ(errno, EINVAL);
1001 }
1002 
FIXTURE(mount_setattr_idmapped)1003 FIXTURE(mount_setattr_idmapped) {
1004 };
1005 
FIXTURE_SETUP(mount_setattr_idmapped)1006 FIXTURE_SETUP(mount_setattr_idmapped)
1007 {
1008 	int img_fd = -EBADF;
1009 
1010 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1011 
1012 	ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0), 0);
1013 
1014 	(void)umount2("/mnt", MNT_DETACH);
1015 	(void)umount2("/tmp", MNT_DETACH);
1016 
1017 	ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV,
1018 			"size=100000,mode=700"), 0);
1019 
1020 	ASSERT_EQ(mkdir("/tmp/B", 0777), 0);
1021 	ASSERT_EQ(mknodat(-EBADF, "/tmp/B/b", S_IFREG | 0644, 0), 0);
1022 	ASSERT_EQ(chown("/tmp/B/b", 0, 0), 0);
1023 
1024 	ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV,
1025 			"size=100000,mode=700"), 0);
1026 
1027 	ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0);
1028 	ASSERT_EQ(mknodat(-EBADF, "/tmp/B/BB/b", S_IFREG | 0644, 0), 0);
1029 	ASSERT_EQ(chown("/tmp/B/BB/b", 0, 0), 0);
1030 
1031 	ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV,
1032 			"size=100000,mode=700"), 0);
1033 
1034 	ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
1035 			"size=100000,mode=700"), 0);
1036 
1037 	ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
1038 
1039 	ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV,
1040 			"size=100000,mode=700"), 0);
1041 
1042 	ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
1043 
1044 	ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
1045 
1046 	ASSERT_EQ(mkdir("/mnt/B", 0777), 0);
1047 
1048 	ASSERT_EQ(mount("testing", "/mnt/B", "ramfs",
1049 			MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0);
1050 
1051 	ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0);
1052 
1053 	ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
1054 			MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
1055 
1056 	ASSERT_EQ(mkdir("/mnt/C", 0777), 0);
1057 	ASSERT_EQ(mkdir("/mnt/D", 0777), 0);
1058 	img_fd = openat(-EBADF, "/mnt/C/ext4.img", O_CREAT | O_WRONLY, 0600);
1059 	ASSERT_GE(img_fd, 0);
1060 	ASSERT_EQ(ftruncate(img_fd, 1024 * 2048), 0);
1061 	ASSERT_EQ(system("mkfs.ext4 -q /mnt/C/ext4.img"), 0);
1062 	ASSERT_EQ(system("mount -o loop -t ext4 /mnt/C/ext4.img /mnt/D/"), 0);
1063 	ASSERT_EQ(close(img_fd), 0);
1064 }
1065 
FIXTURE_TEARDOWN(mount_setattr_idmapped)1066 FIXTURE_TEARDOWN(mount_setattr_idmapped)
1067 {
1068 	(void)umount2("/mnt/A", MNT_DETACH);
1069 	(void)umount2("/tmp", MNT_DETACH);
1070 }
1071 
1072 /**
1073  * Validate that negative fd values are rejected.
1074  */
TEST_F(mount_setattr_idmapped,invalid_fd_negative)1075 TEST_F(mount_setattr_idmapped, invalid_fd_negative)
1076 {
1077 	struct mount_attr attr = {
1078 		.attr_set	= MOUNT_ATTR_IDMAP,
1079 		.userns_fd	= -EBADF,
1080 	};
1081 
1082 	if (!mount_setattr_supported())
1083 		SKIP(return, "mount_setattr syscall not supported");
1084 
1085 	ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1086 		TH_LOG("failure: created idmapped mount with negative fd");
1087 	}
1088 }
1089 
1090 /**
1091  * Validate that excessively large fd values are rejected.
1092  */
TEST_F(mount_setattr_idmapped,invalid_fd_large)1093 TEST_F(mount_setattr_idmapped, invalid_fd_large)
1094 {
1095 	struct mount_attr attr = {
1096 		.attr_set	= MOUNT_ATTR_IDMAP,
1097 		.userns_fd	= INT64_MAX,
1098 	};
1099 
1100 	if (!mount_setattr_supported())
1101 		SKIP(return, "mount_setattr syscall not supported");
1102 
1103 	ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1104 		TH_LOG("failure: created idmapped mount with too large fd value");
1105 	}
1106 }
1107 
1108 /**
1109  * Validate that closed fd values are rejected.
1110  */
TEST_F(mount_setattr_idmapped,invalid_fd_closed)1111 TEST_F(mount_setattr_idmapped, invalid_fd_closed)
1112 {
1113 	int fd;
1114 	struct mount_attr attr = {
1115 		.attr_set = MOUNT_ATTR_IDMAP,
1116 	};
1117 
1118 	if (!mount_setattr_supported())
1119 		SKIP(return, "mount_setattr syscall not supported");
1120 
1121 	fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
1122 	ASSERT_GE(fd, 0);
1123 	ASSERT_GE(close(fd), 0);
1124 
1125 	attr.userns_fd = fd;
1126 	ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1127 		TH_LOG("failure: created idmapped mount with closed fd");
1128 	}
1129 }
1130 
1131 /**
1132  * Validate that the initial user namespace is rejected.
1133  */
TEST_F(mount_setattr_idmapped,invalid_fd_initial_userns)1134 TEST_F(mount_setattr_idmapped, invalid_fd_initial_userns)
1135 {
1136 	int open_tree_fd = -EBADF;
1137 	struct mount_attr attr = {
1138 		.attr_set = MOUNT_ATTR_IDMAP,
1139 	};
1140 
1141 	if (!mount_setattr_supported())
1142 		SKIP(return, "mount_setattr syscall not supported");
1143 
1144 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1145 				     AT_NO_AUTOMOUNT |
1146 				     AT_SYMLINK_NOFOLLOW |
1147 				     OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1148 	ASSERT_GE(open_tree_fd, 0);
1149 
1150 	attr.userns_fd = open("/proc/1/ns/user", O_RDONLY | O_CLOEXEC);
1151 	ASSERT_GE(attr.userns_fd, 0);
1152 	ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1153 	ASSERT_EQ(errno, EPERM);
1154 	ASSERT_EQ(close(attr.userns_fd), 0);
1155 	ASSERT_EQ(close(open_tree_fd), 0);
1156 }
1157 
map_ids(pid_t pid,unsigned long nsid,unsigned long hostid,unsigned long range)1158 static int map_ids(pid_t pid, unsigned long nsid, unsigned long hostid,
1159 		   unsigned long range)
1160 {
1161 	char map[100], procfile[256];
1162 
1163 	snprintf(procfile, sizeof(procfile), "/proc/%d/uid_map", pid);
1164 	snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
1165 	if (write_file(procfile, map, strlen(map)))
1166 		return -1;
1167 
1168 
1169 	snprintf(procfile, sizeof(procfile), "/proc/%d/gid_map", pid);
1170 	snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
1171 	if (write_file(procfile, map, strlen(map)))
1172 		return -1;
1173 
1174 	return 0;
1175 }
1176 
1177 #define __STACK_SIZE (8 * 1024 * 1024)
do_clone(int (* fn)(void *),void * arg,int flags)1178 static pid_t do_clone(int (*fn)(void *), void *arg, int flags)
1179 {
1180 	void *stack;
1181 
1182 	stack = malloc(__STACK_SIZE);
1183 	if (!stack)
1184 		return -ENOMEM;
1185 
1186 #ifdef __ia64__
1187 	return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL);
1188 #else
1189 	return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL);
1190 #endif
1191 }
1192 
get_userns_fd_cb(void * data)1193 static int get_userns_fd_cb(void *data)
1194 {
1195 	return kill(getpid(), SIGSTOP);
1196 }
1197 
wait_for_pid(pid_t pid)1198 static int wait_for_pid(pid_t pid)
1199 {
1200 	int status, ret;
1201 
1202 again:
1203 	ret = waitpid(pid, &status, 0);
1204 	if (ret == -1) {
1205 		if (errno == EINTR)
1206 			goto again;
1207 
1208 		return -1;
1209 	}
1210 
1211 	if (!WIFEXITED(status))
1212 		return -1;
1213 
1214 	return WEXITSTATUS(status);
1215 }
1216 
get_userns_fd(unsigned long nsid,unsigned long hostid,unsigned long range)1217 static int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range)
1218 {
1219 	int ret;
1220 	pid_t pid;
1221 	char path[256];
1222 
1223 	pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER);
1224 	if (pid < 0)
1225 		return -errno;
1226 
1227 	ret = map_ids(pid, nsid, hostid, range);
1228 	if (ret < 0)
1229 		return ret;
1230 
1231 	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
1232 	ret = open(path, O_RDONLY | O_CLOEXEC);
1233 	kill(pid, SIGKILL);
1234 	wait_for_pid(pid);
1235 	return ret;
1236 }
1237 
1238 /**
1239  * Validate that an attached mount in our mount namespace cannot be idmapped.
1240  * (The kernel enforces that the mount's mount namespace and the caller's mount
1241  *  namespace match.)
1242  */
TEST_F(mount_setattr_idmapped,attached_mount_inside_current_mount_namespace)1243 TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace)
1244 {
1245 	int open_tree_fd = -EBADF;
1246 	struct mount_attr attr = {
1247 		.attr_set = MOUNT_ATTR_IDMAP,
1248 	};
1249 
1250 	if (!mount_setattr_supported())
1251 		SKIP(return, "mount_setattr syscall not supported");
1252 
1253 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1254 				     AT_EMPTY_PATH |
1255 				     AT_NO_AUTOMOUNT |
1256 				     AT_SYMLINK_NOFOLLOW |
1257 				     OPEN_TREE_CLOEXEC);
1258 	ASSERT_GE(open_tree_fd, 0);
1259 
1260 	attr.userns_fd	= get_userns_fd(0, 10000, 10000);
1261 	ASSERT_GE(attr.userns_fd, 0);
1262 	ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1263 	ASSERT_EQ(close(attr.userns_fd), 0);
1264 	ASSERT_EQ(close(open_tree_fd), 0);
1265 }
1266 
1267 /**
1268  * Validate that idmapping a mount is rejected if the mount's mount namespace
1269  * and our mount namespace don't match.
1270  * (The kernel enforces that the mount's mount namespace and the caller's mount
1271  *  namespace match.)
1272  */
TEST_F(mount_setattr_idmapped,attached_mount_outside_current_mount_namespace)1273 TEST_F(mount_setattr_idmapped, attached_mount_outside_current_mount_namespace)
1274 {
1275 	int open_tree_fd = -EBADF;
1276 	struct mount_attr attr = {
1277 		.attr_set = MOUNT_ATTR_IDMAP,
1278 	};
1279 
1280 	if (!mount_setattr_supported())
1281 		SKIP(return, "mount_setattr syscall not supported");
1282 
1283 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1284 				     AT_EMPTY_PATH |
1285 				     AT_NO_AUTOMOUNT |
1286 				     AT_SYMLINK_NOFOLLOW |
1287 				     OPEN_TREE_CLOEXEC);
1288 	ASSERT_GE(open_tree_fd, 0);
1289 
1290 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1291 
1292 	attr.userns_fd	= get_userns_fd(0, 10000, 10000);
1293 	ASSERT_GE(attr.userns_fd, 0);
1294 	ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
1295 				    sizeof(attr)), 0);
1296 	ASSERT_EQ(close(attr.userns_fd), 0);
1297 	ASSERT_EQ(close(open_tree_fd), 0);
1298 }
1299 
1300 /**
1301  * Validate that an attached mount in our mount namespace can be idmapped.
1302  */
TEST_F(mount_setattr_idmapped,detached_mount_inside_current_mount_namespace)1303 TEST_F(mount_setattr_idmapped, detached_mount_inside_current_mount_namespace)
1304 {
1305 	int open_tree_fd = -EBADF;
1306 	struct mount_attr attr = {
1307 		.attr_set = MOUNT_ATTR_IDMAP,
1308 	};
1309 
1310 	if (!mount_setattr_supported())
1311 		SKIP(return, "mount_setattr syscall not supported");
1312 
1313 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1314 				     AT_EMPTY_PATH |
1315 				     AT_NO_AUTOMOUNT |
1316 				     AT_SYMLINK_NOFOLLOW |
1317 				     OPEN_TREE_CLOEXEC |
1318 				     OPEN_TREE_CLONE);
1319 	ASSERT_GE(open_tree_fd, 0);
1320 
1321 	/* Changing mount properties on a detached mount. */
1322 	attr.userns_fd	= get_userns_fd(0, 10000, 10000);
1323 	ASSERT_GE(attr.userns_fd, 0);
1324 	ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1325 				    AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1326 	ASSERT_EQ(close(attr.userns_fd), 0);
1327 	ASSERT_EQ(close(open_tree_fd), 0);
1328 }
1329 
1330 /**
1331  * Validate that a detached mount not in our mount namespace can be idmapped.
1332  */
TEST_F(mount_setattr_idmapped,detached_mount_outside_current_mount_namespace)1333 TEST_F(mount_setattr_idmapped, detached_mount_outside_current_mount_namespace)
1334 {
1335 	int open_tree_fd = -EBADF;
1336 	struct mount_attr attr = {
1337 		.attr_set = MOUNT_ATTR_IDMAP,
1338 	};
1339 
1340 	if (!mount_setattr_supported())
1341 		SKIP(return, "mount_setattr syscall not supported");
1342 
1343 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1344 				     AT_EMPTY_PATH |
1345 				     AT_NO_AUTOMOUNT |
1346 				     AT_SYMLINK_NOFOLLOW |
1347 				     OPEN_TREE_CLOEXEC |
1348 				     OPEN_TREE_CLONE);
1349 	ASSERT_GE(open_tree_fd, 0);
1350 
1351 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1352 
1353 	/* Changing mount properties on a detached mount. */
1354 	attr.userns_fd	= get_userns_fd(0, 10000, 10000);
1355 	ASSERT_GE(attr.userns_fd, 0);
1356 	ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1357 				    AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1358 	ASSERT_EQ(close(attr.userns_fd), 0);
1359 	ASSERT_EQ(close(open_tree_fd), 0);
1360 }
1361 
1362 /**
1363  * Validate that currently changing the idmapping of an idmapped mount fails.
1364  */
TEST_F(mount_setattr_idmapped,change_idmapping)1365 TEST_F(mount_setattr_idmapped, change_idmapping)
1366 {
1367 	int open_tree_fd = -EBADF;
1368 	struct mount_attr attr = {
1369 		.attr_set = MOUNT_ATTR_IDMAP,
1370 	};
1371 
1372 	if (!mount_setattr_supported())
1373 		SKIP(return, "mount_setattr syscall not supported");
1374 
1375 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1376 				     AT_EMPTY_PATH |
1377 				     AT_NO_AUTOMOUNT |
1378 				     AT_SYMLINK_NOFOLLOW |
1379 				     OPEN_TREE_CLOEXEC |
1380 				     OPEN_TREE_CLONE);
1381 	ASSERT_GE(open_tree_fd, 0);
1382 
1383 	attr.userns_fd	= get_userns_fd(0, 10000, 10000);
1384 	ASSERT_GE(attr.userns_fd, 0);
1385 	ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1386 				    AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1387 	ASSERT_EQ(close(attr.userns_fd), 0);
1388 
1389 	/* Change idmapping on a detached mount that is already idmapped. */
1390 	attr.userns_fd	= get_userns_fd(0, 20000, 10000);
1391 	ASSERT_GE(attr.userns_fd, 0);
1392 	ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1393 	ASSERT_EQ(close(attr.userns_fd), 0);
1394 	ASSERT_EQ(close(open_tree_fd), 0);
1395 }
1396 
expected_uid_gid(int dfd,const char * path,int flags,uid_t expected_uid,gid_t expected_gid)1397 static bool expected_uid_gid(int dfd, const char *path, int flags,
1398 			     uid_t expected_uid, gid_t expected_gid)
1399 {
1400 	int ret;
1401 	struct stat st;
1402 
1403 	ret = fstatat(dfd, path, &st, flags);
1404 	if (ret < 0)
1405 		return false;
1406 
1407 	return st.st_uid == expected_uid && st.st_gid == expected_gid;
1408 }
1409 
TEST_F(mount_setattr_idmapped,idmap_mount_tree_invalid)1410 TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
1411 {
1412 	int open_tree_fd = -EBADF;
1413 	struct mount_attr attr = {
1414 		.attr_set = MOUNT_ATTR_IDMAP,
1415 	};
1416 
1417 	if (!mount_setattr_supported())
1418 		SKIP(return, "mount_setattr syscall not supported");
1419 
1420 	ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
1421 	ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
1422 
1423 	open_tree_fd = sys_open_tree(-EBADF, "/mnt/A",
1424 				     AT_RECURSIVE |
1425 				     AT_EMPTY_PATH |
1426 				     AT_NO_AUTOMOUNT |
1427 				     AT_SYMLINK_NOFOLLOW |
1428 				     OPEN_TREE_CLOEXEC |
1429 				     OPEN_TREE_CLONE);
1430 	ASSERT_GE(open_tree_fd, 0);
1431 
1432 	attr.userns_fd	= get_userns_fd(0, 10000, 10000);
1433 	ASSERT_GE(attr.userns_fd, 0);
1434 	ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1435 	ASSERT_EQ(close(attr.userns_fd), 0);
1436 	ASSERT_EQ(close(open_tree_fd), 0);
1437 
1438 	ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
1439 	ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
1440 	ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/b", 0, 0, 0), 0);
1441 	ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0);
1442 }
1443 
TEST_F(mount_setattr,mount_attr_nosymfollow)1444 TEST_F(mount_setattr, mount_attr_nosymfollow)
1445 {
1446 	int fd;
1447 	unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
1448 	struct mount_attr attr = {
1449 		.attr_set	= MOUNT_ATTR_NOSYMFOLLOW,
1450 	};
1451 
1452 	if (!mount_setattr_supported())
1453 		SKIP(return, "mount_setattr syscall not supported");
1454 
1455 	fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1456 	ASSERT_GT(fd, 0);
1457 	ASSERT_EQ(close(fd), 0);
1458 
1459 	old_flags = read_mnt_flags("/mnt/A");
1460 	ASSERT_GT(old_flags, 0);
1461 
1462 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
1463 
1464 	expected_flags = old_flags;
1465 	expected_flags |= ST_NOSYMFOLLOW;
1466 
1467 	new_flags = read_mnt_flags("/mnt/A");
1468 	ASSERT_EQ(new_flags, expected_flags);
1469 
1470 	new_flags = read_mnt_flags("/mnt/A/AA");
1471 	ASSERT_EQ(new_flags, expected_flags);
1472 
1473 	new_flags = read_mnt_flags("/mnt/A/AA/B");
1474 	ASSERT_EQ(new_flags, expected_flags);
1475 
1476 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
1477 	ASSERT_EQ(new_flags, expected_flags);
1478 
1479 	fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1480 	ASSERT_LT(fd, 0);
1481 	ASSERT_EQ(errno, ELOOP);
1482 
1483 	attr.attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW;
1484 	attr.attr_clr |= MOUNT_ATTR_NOSYMFOLLOW;
1485 
1486 	ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
1487 
1488 	expected_flags &= ~ST_NOSYMFOLLOW;
1489 	new_flags = read_mnt_flags("/mnt/A");
1490 	ASSERT_EQ(new_flags, expected_flags);
1491 
1492 	new_flags = read_mnt_flags("/mnt/A/AA");
1493 	ASSERT_EQ(new_flags, expected_flags);
1494 
1495 	new_flags = read_mnt_flags("/mnt/A/AA/B");
1496 	ASSERT_EQ(new_flags, expected_flags);
1497 
1498 	new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
1499 	ASSERT_EQ(new_flags, expected_flags);
1500 
1501 	fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1502 	ASSERT_GT(fd, 0);
1503 	ASSERT_EQ(close(fd), 0);
1504 }
1505 
1506 TEST_HARNESS_MAIN
1507