xref: /linux/tools/testing/selftests/filesystems/empty_mntns/nullfs_atime_test.c (revision 8e8cd9a4c6dc006e9bd51b8ad0079fb4576b48d3)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * The root of every empty mount namespace is the same nullfs inode. A read
4  * of it by one user must not change the access time another user sees.
5  */
6 #define _GNU_SOURCE
7 #include <dirent.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sched.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 
18 #include "../../kselftest_harness.h"
19 
20 #ifndef UNSHARE_EMPTY_MNTNS
21 #define UNSHARE_EMPTY_MNTNS	0x00100000
22 #endif
23 
24 enum {
25 	CHILD_OK,
26 	CHILD_UNSUPPORTED,
27 	CHILD_SETUP,
28 	CHILD_CHANGED,
29 };
30 
wait_byte(int fd)31 static int wait_byte(int fd)
32 {
33 	char c;
34 
35 	return read(fd, &c, 1) == 1 ? 0 : -1;
36 }
37 
send_byte(int fd)38 static int send_byte(int fd)
39 {
40 	return write(fd, "x", 1) == 1 ? 0 : -1;
41 }
42 
empty_mntns(void)43 static int empty_mntns(void)
44 {
45 	if (!unshare(UNSHARE_EMPTY_MNTNS))
46 		return 0;
47 	return errno == EINVAL ? CHILD_UNSUPPORTED : CHILD_SETUP;
48 }
49 
50 /* the watcher: stats its root before and after the reader read its own */
watcher(int to_reader,int from_reader)51 static int watcher(int to_reader, int from_reader)
52 {
53 	struct stat before, after;
54 	int ret;
55 
56 	ret = empty_mntns();
57 	if (ret)
58 		return ret;
59 	if (stat("/", &before))
60 		return CHILD_SETUP;
61 	if (send_byte(to_reader) || wait_byte(from_reader))
62 		return CHILD_SETUP;
63 	if (stat("/", &after))
64 		return CHILD_SETUP;
65 	if (before.st_atim.tv_sec != after.st_atim.tv_sec ||
66 	    before.st_atim.tv_nsec != after.st_atim.tv_nsec)
67 		return CHILD_CHANGED;
68 	return CHILD_OK;
69 }
70 
71 /* the reader: lists its own root, which is the same inode */
reader(int to_watcher,int from_watcher)72 static int reader(int to_watcher, int from_watcher)
73 {
74 	struct dirent *de;
75 	DIR *d;
76 	int ret;
77 
78 	ret = empty_mntns();
79 	if (ret)
80 		return ret;
81 	if (wait_byte(from_watcher))
82 		return CHILD_SETUP;
83 	d = opendir("/");
84 	if (!d)
85 		return CHILD_SETUP;
86 	while ((de = readdir(d)))
87 		;
88 	closedir(d);
89 	return send_byte(to_watcher) ? CHILD_SETUP : CHILD_OK;
90 }
91 
wait_child(pid_t pid)92 static int wait_child(pid_t pid)
93 {
94 	int status;
95 
96 	if (waitpid(pid, &status, 0) != pid || !WIFEXITED(status))
97 		return -1;
98 	return WEXITSTATUS(status);
99 }
100 
TEST(empty_mntns_root_atime)101 TEST(empty_mntns_root_atime)
102 {
103 	int to_reader[2], to_watcher[2], w, r;
104 	pid_t watcher_pid, reader_pid;
105 
106 	if (geteuid())
107 		SKIP(return, "test requires root");
108 	ASSERT_EQ(pipe(to_reader), 0);
109 	ASSERT_EQ(pipe(to_watcher), 0);
110 
111 	watcher_pid = fork();
112 	ASSERT_GE(watcher_pid, 0);
113 	if (watcher_pid == 0)
114 		_exit(watcher(to_reader[1], to_watcher[0]));
115 	reader_pid = fork();
116 	ASSERT_GE(reader_pid, 0);
117 	if (reader_pid == 0)
118 		_exit(reader(to_watcher[1], to_reader[0]));
119 
120 	r = wait_child(reader_pid);
121 	w = wait_child(watcher_pid);
122 	if (r == CHILD_UNSUPPORTED || w == CHILD_UNSUPPORTED)
123 		SKIP(return, "UNSHARE_EMPTY_MNTNS not supported");
124 	EXPECT_EQ(r, CHILD_OK);
125 	EXPECT_EQ(w, CHILD_OK)
126 		TH_LOG("the access time of the root changed while this namespace did nothing");
127 }
128 
129 TEST_HARNESS_MAIN
130