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 31 static int wait_byte(int fd) 32 { 33 char c; 34 35 return read(fd, &c, 1) == 1 ? 0 : -1; 36 } 37 38 static int send_byte(int fd) 39 { 40 return write(fd, "x", 1) == 1 ? 0 : -1; 41 } 42 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 */ 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 */ 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 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 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