aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-11-04 07:43:08 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2019-01-30 17:44:25 -0500
commit132e460848f4261b8a6b9c28fae52bf9e02b52fd (patch)
tree6efa9049652905a5931b564a64d0aa609979d91b
parenta0c9a8b8fd9fd572b0d60276beb2142c8f59f9b8 (diff)
new helper: do_new_mount_fc()
Create an fs_context-aware version of do_new_mount(). This takes an fs_context with a superblock already attached to it. Make do_new_mount() use do_new_mount_fc() rather than do_new_mount(); this allows the consolidation of the mount creation, check and add steps. To make this work, mount_too_revealing() is changed to take a superblock rather than a mount (which the fs_context doesn't have available), allowing this check to be done before the mount object is created. Signed-off-by: David Howells <dhowells@redhat.com> Co-developed-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namespace.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 0354cb6ac2d3..f629e1c7f3cc 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2523,7 +2523,37 @@ unlock:
2523 return err; 2523 return err;
2524} 2524}
2525 2525
2526static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags); 2526static bool mount_too_revealing(const struct super_block *sb, int *new_mnt_flags);
2527
2528/*
2529 * Create a new mount using a superblock configuration and request it
2530 * be added to the namespace tree.
2531 */
2532static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,
2533 unsigned int mnt_flags)
2534{
2535 struct vfsmount *mnt;
2536 struct super_block *sb = fc->root->d_sb;
2537 int error;
2538
2539 if (mount_too_revealing(sb, &mnt_flags)) {
2540 dput(fc->root);
2541 fc->root = NULL;
2542 deactivate_locked_super(sb);
2543 return -EPERM;
2544 }
2545
2546 up_write(&sb->s_umount);
2547
2548 mnt = vfs_create_mount(fc);
2549 if (IS_ERR(mnt))
2550 return PTR_ERR(mnt);
2551
2552 error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
2553 if (error < 0)
2554 mntput(mnt);
2555 return error;
2556}
2527 2557
2528/* 2558/*
2529 * create a new mount for userspace and request it to be added into the 2559 * create a new mount for userspace and request it to be added into the
@@ -2533,7 +2563,6 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
2533 int mnt_flags, const char *name, void *data) 2563 int mnt_flags, const char *name, void *data)
2534{ 2564{
2535 struct file_system_type *type; 2565 struct file_system_type *type;
2536 struct vfsmount *mnt;
2537 struct fs_context *fc; 2566 struct fs_context *fc;
2538 const char *subtype = NULL; 2567 const char *subtype = NULL;
2539 int err = 0; 2568 int err = 0;
@@ -2577,26 +2606,9 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
2577 err = parse_monolithic_mount_data(fc, data); 2606 err = parse_monolithic_mount_data(fc, data);
2578 if (!err) 2607 if (!err)
2579 err = vfs_get_tree(fc); 2608 err = vfs_get_tree(fc);
2580 if (err) 2609 if (!err)
2581 goto out; 2610 err = do_new_mount_fc(fc, path, mnt_flags);
2582
2583 up_write(&fc->root->d_sb->s_umount);
2584 mnt = vfs_create_mount(fc);
2585 if (IS_ERR(mnt)) {
2586 err = PTR_ERR(mnt);
2587 goto out;
2588 }
2589
2590 if (mount_too_revealing(mnt, &mnt_flags)) {
2591 mntput(mnt);
2592 err = -EPERM;
2593 goto out;
2594 }
2595 2611
2596 err = do_add_mount(real_mount(mnt), path, mnt_flags);
2597 if (err)
2598 mntput(mnt);
2599out:
2600 put_fs_context(fc); 2612 put_fs_context(fc);
2601 return err; 2613 return err;
2602} 2614}
@@ -3421,7 +3433,8 @@ bool current_chrooted(void)
3421 return chrooted; 3433 return chrooted;
3422} 3434}
3423 3435
3424static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new, 3436static bool mnt_already_visible(struct mnt_namespace *ns,
3437 const struct super_block *sb,
3425 int *new_mnt_flags) 3438 int *new_mnt_flags)
3426{ 3439{
3427 int new_flags = *new_mnt_flags; 3440 int new_flags = *new_mnt_flags;
@@ -3433,7 +3446,7 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
3433 struct mount *child; 3446 struct mount *child;
3434 int mnt_flags; 3447 int mnt_flags;
3435 3448
3436 if (mnt->mnt.mnt_sb->s_type != new->mnt_sb->s_type) 3449 if (mnt->mnt.mnt_sb->s_type != sb->s_type)
3437 continue; 3450 continue;
3438 3451
3439 /* This mount is not fully visible if it's root directory 3452 /* This mount is not fully visible if it's root directory
@@ -3484,7 +3497,7 @@ found:
3484 return visible; 3497 return visible;
3485} 3498}
3486 3499
3487static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags) 3500static bool mount_too_revealing(const struct super_block *sb, int *new_mnt_flags)
3488{ 3501{
3489 const unsigned long required_iflags = SB_I_NOEXEC | SB_I_NODEV; 3502 const unsigned long required_iflags = SB_I_NOEXEC | SB_I_NODEV;
3490 struct mnt_namespace *ns = current->nsproxy->mnt_ns; 3503 struct mnt_namespace *ns = current->nsproxy->mnt_ns;
@@ -3494,7 +3507,7 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
3494 return false; 3507 return false;
3495 3508
3496 /* Can this filesystem be too revealing? */ 3509 /* Can this filesystem be too revealing? */
3497 s_iflags = mnt->mnt_sb->s_iflags; 3510 s_iflags = sb->s_iflags;
3498 if (!(s_iflags & SB_I_USERNS_VISIBLE)) 3511 if (!(s_iflags & SB_I_USERNS_VISIBLE))
3499 return false; 3512 return false;
3500 3513
@@ -3504,7 +3517,7 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
3504 return true; 3517 return true;
3505 } 3518 }
3506 3519
3507 return !mnt_already_visible(ns, mnt, new_mnt_flags); 3520 return !mnt_already_visible(ns, sb, new_mnt_flags);
3508} 3521}
3509 3522
3510bool mnt_may_suid(struct vfsmount *mnt) 3523bool mnt_may_suid(struct vfsmount *mnt)