Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull mount fixes from Al Viro:
"Fixes for several recent mount-related regressions"

* tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
change_mnt_propagation(): calculate propagation source only if we'll need it
use uniform permission checks for all mount propagation changes
propagate_umount(): only surviving overmounts should be reparented
fix the softlockups in attach_recursive_mnt()

+28 -23
+22 -19
fs/namespace.c
··· 1197 1197 1198 1198 if (!mnt_ns_attached(mnt)) { 1199 1199 for (struct mount *m = mnt; m; m = next_mnt(m, mnt)) 1200 - if (unlikely(mnt_ns_attached(m))) 1201 - m = skip_mnt_tree(m); 1202 - else 1203 - mnt_add_to_ns(n, m); 1200 + mnt_add_to_ns(n, m); 1204 1201 n->nr_mounts += n->pending_mounts; 1205 1202 n->pending_mounts = 0; 1206 1203 } ··· 2701 2704 lock_mnt_tree(child); 2702 2705 q = __lookup_mnt(&child->mnt_parent->mnt, 2703 2706 child->mnt_mountpoint); 2707 + commit_tree(child); 2704 2708 if (q) { 2705 2709 struct mountpoint *mp = root.mp; 2706 2710 struct mount *r = child; ··· 2711 2713 mp = shorter; 2712 2714 mnt_change_mountpoint(r, mp, q); 2713 2715 } 2714 - commit_tree(child); 2715 2716 } 2716 2717 unpin_mountpoint(&root); 2717 2718 unlock_mount_hash(); ··· 2859 2862 return attach_recursive_mnt(mnt, p, mp); 2860 2863 } 2861 2864 2865 + static int may_change_propagation(const struct mount *m) 2866 + { 2867 + struct mnt_namespace *ns = m->mnt_ns; 2868 + 2869 + // it must be mounted in some namespace 2870 + if (IS_ERR_OR_NULL(ns)) // is_mounted() 2871 + return -EINVAL; 2872 + // and the caller must be admin in userns of that namespace 2873 + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) 2874 + return -EPERM; 2875 + return 0; 2876 + } 2877 + 2862 2878 /* 2863 2879 * Sanity check the flags to change_mnt_propagation. 2864 2880 */ ··· 2908 2898 return -EINVAL; 2909 2899 2910 2900 namespace_lock(); 2911 - if (!check_mnt(mnt)) { 2912 - err = -EINVAL; 2901 + err = may_change_propagation(mnt); 2902 + if (err) 2913 2903 goto out_unlock; 2914 - } 2904 + 2915 2905 if (type == MS_SHARED) { 2916 2906 err = invent_group_ids(mnt, recurse); 2917 2907 if (err) ··· 3357 3347 3358 3348 namespace_lock(); 3359 3349 3360 - err = -EINVAL; 3361 - /* To and From must be mounted */ 3362 - if (!is_mounted(&from->mnt)) 3350 + err = may_change_propagation(from); 3351 + if (err) 3363 3352 goto out; 3364 - if (!is_mounted(&to->mnt)) 3365 - goto out; 3366 - 3367 - err = -EPERM; 3368 - /* We should be allowed to modify mount namespaces of both mounts */ 3369 - if (!ns_capable(from->mnt_ns->user_ns, CAP_SYS_ADMIN)) 3370 - goto out; 3371 - if (!ns_capable(to->mnt_ns->user_ns, CAP_SYS_ADMIN)) 3353 + err = may_change_propagation(to); 3354 + if (err) 3372 3355 goto out; 3373 3356 3374 3357 err = -EINVAL;
+6 -4
fs/pnode.c
··· 111 111 return; 112 112 } 113 113 if (IS_MNT_SHARED(mnt)) { 114 - m = propagation_source(mnt); 114 + if (type == MS_SLAVE || !hlist_empty(&mnt->mnt_slave_list)) 115 + m = propagation_source(mnt); 115 116 if (list_empty(&mnt->mnt_share)) { 116 117 mnt_release_group_id(mnt); 117 118 } else { ··· 638 637 } 639 638 640 639 // now to_umount consists of all acceptable candidates 641 - // deal with reparenting of remaining overmounts on those 640 + // deal with reparenting of surviving overmounts on those 642 641 list_for_each_entry(m, &to_umount, mnt_list) { 643 - if (m->overmount) 644 - reparent(m->overmount); 642 + struct mount *over = m->overmount; 643 + if (over && !will_be_unmounted(over)) 644 + reparent(over); 645 645 } 646 646 647 647 // and fold them into the set