Commit fa0bad3f28a7c4a192769a128ede584c49a7e12f

Authored by Eric W. Biederman
Committed by Greg Kroah-Hartman
1 parent 80d4d8397a

mnt: Update unprivileged remount test

commit 4a44a19b470a886997d6647a77bb3e38dcbfa8c5 upstream.

- 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.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 1 changed file with 142 additions and 30 deletions Side-by-side Diff

tools/testing/selftests/mount/unprivileged-remount-test.c
... ... @@ -6,6 +6,8 @@
6 6 #include <sys/types.h>
7 7 #include <sys/mount.h>
8 8 #include <sys/wait.h>
  9 +#include <sys/vfs.h>
  10 +#include <sys/statvfs.h>
9 11 #include <stdlib.h>
10 12 #include <unistd.h>
11 13 #include <fcntl.h>
12 14  
13 15  
... ... @@ -32,11 +34,14 @@
32 34 # define CLONE_NEWPID 0x20000000
33 35 #endif
34 36  
  37 +#ifndef MS_REC
  38 +# define MS_REC 16384
  39 +#endif
35 40 #ifndef MS_RELATIME
36   -#define MS_RELATIME (1 << 21)
  41 +# define MS_RELATIME (1 << 21)
37 42 #endif
38 43 #ifndef MS_STRICTATIME
39   -#define MS_STRICTATIME (1 << 24)
  44 +# define MS_STRICTATIME (1 << 24)
40 45 #endif
41 46  
42 47 static void die(char *fmt, ...)
... ... @@ -87,6 +92,45 @@
87 92 }
88 93 }
89 94  
  95 +static 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 +
90 134 static void create_and_enter_userns(void)
91 135 {
92 136 uid_t uid;
... ... @@ -118,7 +162,8 @@
118 162 }
119 163  
120 164 static
121   -bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags)
  165 +bool test_unpriv_remount(const char *fstype, const char *mount_options,
  166 + int mount_flags, int remount_flags, int invalid_flags)
122 167 {
123 168 pid_t child;
124 169  
... ... @@ -151,9 +196,11 @@
151 196 strerror(errno));
152 197 }
153 198  
154   - if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) {
155   - die("mount of /tmp failed: %s\n",
156   - strerror(errno));
  199 + if (mount("testing", "/tmp", fstype, mount_flags, mount_options) != 0) {
  200 + die("mount of %s with options '%s' on /tmp failed: %s\n",
  201 + fstype,
  202 + mount_options? mount_options : "",
  203 + strerror(errno));
157 204 }
158 205  
159 206 create_and_enter_userns();
160 207  
161 208  
162 209  
163 210  
164 211  
165 212  
166 213  
167 214  
168 215  
169 216  
170 217  
171 218  
172 219  
173 220  
174 221  
175 222  
176 223  
177 224  
... ... @@ -181,62 +228,127 @@
181 228  
182 229 static 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  
187 234 static 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);
190 238 }
191 239  
  240 +static 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);
  300 +}
  301 +
192 302 int 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 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 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 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 314 die("MS_NOEXEC malfunctions\n");
205 315 }
206   - if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV,
207   - MS_NOATIME|MS_NODEV))
  316 + if (!test_unpriv_remount_atime(MS_RELATIME,
  317 + MS_NOATIME))
208 318 {
209 319 die("MS_RELATIME malfunctions\n");
210 320 }
211   - if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV,
212   - MS_NOATIME|MS_NODEV))
  321 + if (!test_unpriv_remount_atime(MS_STRICTATIME,
  322 + MS_NOATIME))
213 323 {
214 324 die("MS_STRICTATIME malfunctions\n");
215 325 }
216   - if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV,
217   - MS_STRICTATIME|MS_NODEV))
  326 + if (!test_unpriv_remount_atime(MS_NOATIME,
  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,
222   - MS_NOATIME|MS_NODEV))
  331 + if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME,
  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,
227   - MS_NOATIME|MS_NODEV))
  336 + if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME,
  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,
232   - MS_STRICTATIME|MS_NODEV))
  341 + if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME,
  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,
237   - MS_NOATIME|MS_NODEV))
  346 + if (!test_unpriv_remount("ramfs", NULL, MS_STRICTATIME, 0, MS_NOATIME))
238 347 {
239 348 die("Default atime malfunctions\n");
  349 + }
  350 + if (!test_priv_mount_unpriv_remount()) {
  351 + die("Mount flags unexpectedly changed after remount\n");
240 352 }
241 353 return EXIT_SUCCESS;
242 354 }