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