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

saner handling of temporary namespaces

mount_subtree() creates (and soon destroys) a temporary namespace,
so that automounts could function normally. These beasts should
never become anyone's current namespaces; they don't, but it would
be better to make prevention of that more straightforward. And
since they don't become anyone's current namespace, we don't need
to bother with reserving procfs inums for those.

Teach alloc_mnt_ns() to skip inum allocation if told so, adjust
put_mnt_ns() accordingly, make mount_subtree() use temporary
(anon) namespace. is_anon_ns() checks if a namespace is such.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 74e83122 3bd045cc

+40 -39
+5
fs/mount.h
··· 146 146 147 147 return __is_local_mountpoint(dentry); 148 148 } 149 + 150 + static inline bool is_anon_ns(struct mnt_namespace *ns) 151 + { 152 + return ns->seq == 0; 153 + }
+35 -39
fs/namespace.c
··· 2873 2873 2874 2874 static void free_mnt_ns(struct mnt_namespace *ns) 2875 2875 { 2876 - ns_free_inum(&ns->ns); 2876 + if (!is_anon_ns(ns)) 2877 + ns_free_inum(&ns->ns); 2877 2878 dec_mnt_namespaces(ns->ucounts); 2878 2879 put_user_ns(ns->user_ns); 2879 2880 kfree(ns); ··· 2889 2888 */ 2890 2889 static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); 2891 2890 2892 - static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) 2891 + static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool anon) 2893 2892 { 2894 2893 struct mnt_namespace *new_ns; 2895 2894 struct ucounts *ucounts; ··· 2899 2898 if (!ucounts) 2900 2899 return ERR_PTR(-ENOSPC); 2901 2900 2902 - new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); 2901 + new_ns = kzalloc(sizeof(struct mnt_namespace), GFP_KERNEL); 2903 2902 if (!new_ns) { 2904 2903 dec_mnt_namespaces(ucounts); 2905 2904 return ERR_PTR(-ENOMEM); 2906 2905 } 2907 - ret = ns_alloc_inum(&new_ns->ns); 2908 - if (ret) { 2909 - kfree(new_ns); 2910 - dec_mnt_namespaces(ucounts); 2911 - return ERR_PTR(ret); 2906 + if (!anon) { 2907 + ret = ns_alloc_inum(&new_ns->ns); 2908 + if (ret) { 2909 + kfree(new_ns); 2910 + dec_mnt_namespaces(ucounts); 2911 + return ERR_PTR(ret); 2912 + } 2912 2913 } 2913 2914 new_ns->ns.ops = &mntns_operations; 2914 - new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); 2915 + if (!anon) 2916 + new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); 2915 2917 atomic_set(&new_ns->count, 1); 2916 - new_ns->root = NULL; 2917 2918 INIT_LIST_HEAD(&new_ns->list); 2918 2919 init_waitqueue_head(&new_ns->poll); 2919 - new_ns->event = 0; 2920 2920 new_ns->user_ns = get_user_ns(user_ns); 2921 2921 new_ns->ucounts = ucounts; 2922 - new_ns->mounts = 0; 2923 - new_ns->pending_mounts = 0; 2924 2922 return new_ns; 2925 2923 } 2926 2924 ··· 2943 2943 2944 2944 old = ns->root; 2945 2945 2946 - new_ns = alloc_mnt_ns(user_ns); 2946 + new_ns = alloc_mnt_ns(user_ns, false); 2947 2947 if (IS_ERR(new_ns)) 2948 2948 return new_ns; 2949 2949 ··· 3003 3003 return new_ns; 3004 3004 } 3005 3005 3006 - /** 3007 - * create_mnt_ns - creates a private namespace and adds a root filesystem 3008 - * @mnt: pointer to the new root filesystem mountpoint 3009 - */ 3010 - static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) 3006 + struct dentry *mount_subtree(struct vfsmount *m, const char *name) 3011 3007 { 3012 - struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns); 3013 - if (!IS_ERR(new_ns)) { 3014 - struct mount *mnt = real_mount(m); 3015 - mnt->mnt_ns = new_ns; 3016 - new_ns->root = mnt; 3017 - new_ns->mounts++; 3018 - list_add(&mnt->mnt_list, &new_ns->list); 3019 - } else { 3020 - mntput(m); 3021 - } 3022 - return new_ns; 3023 - } 3024 - 3025 - struct dentry *mount_subtree(struct vfsmount *mnt, const char *name) 3026 - { 3008 + struct mount *mnt = real_mount(m); 3027 3009 struct mnt_namespace *ns; 3028 3010 struct super_block *s; 3029 3011 struct path path; 3030 3012 int err; 3031 3013 3032 - ns = create_mnt_ns(mnt); 3033 - if (IS_ERR(ns)) 3014 + ns = alloc_mnt_ns(&init_user_ns, true); 3015 + if (IS_ERR(ns)) { 3016 + mntput(m); 3034 3017 return ERR_CAST(ns); 3018 + } 3019 + mnt->mnt_ns = ns; 3020 + ns->root = mnt; 3021 + ns->mounts++; 3022 + list_add(&mnt->mnt_list, &ns->list); 3035 3023 3036 - err = vfs_path_lookup(mnt->mnt_root, mnt, 3024 + err = vfs_path_lookup(m->mnt_root, m, 3037 3025 name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); 3038 3026 3039 3027 put_mnt_ns(ns); ··· 3231 3243 static void __init init_mount_tree(void) 3232 3244 { 3233 3245 struct vfsmount *mnt; 3246 + struct mount *m; 3234 3247 struct mnt_namespace *ns; 3235 3248 struct path root; 3236 3249 struct file_system_type *type; ··· 3244 3255 if (IS_ERR(mnt)) 3245 3256 panic("Can't create rootfs"); 3246 3257 3247 - ns = create_mnt_ns(mnt); 3258 + ns = alloc_mnt_ns(&init_user_ns, false); 3248 3259 if (IS_ERR(ns)) 3249 3260 panic("Can't allocate initial namespace"); 3250 - 3261 + m = real_mount(mnt); 3262 + m->mnt_ns = ns; 3263 + ns->root = m; 3264 + ns->mounts = 1; 3265 + list_add(&m->mnt_list, &ns->list); 3251 3266 init_task.nsproxy->mnt_ns = ns; 3252 3267 get_mnt_ns(ns); 3253 3268 ··· 3491 3498 !ns_capable(current_user_ns(), CAP_SYS_CHROOT) || 3492 3499 !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) 3493 3500 return -EPERM; 3501 + 3502 + if (is_anon_ns(mnt_ns)) 3503 + return -EINVAL; 3494 3504 3495 3505 if (fs->users != 1) 3496 3506 return -EINVAL;