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

vfs: Add a user namespace reference from struct mnt_namespace

This will allow for support for unprivileged mounts in a new user namespace.

Acked-by: "Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>

+20 -10
+1
fs/mount.h
··· 6 6 atomic_t count; 7 7 struct mount * root; 8 8 struct list_head list; 9 + struct user_namespace *user_ns; 9 10 u64 seq; /* Sequence number to prevent loops */ 10 11 wait_queue_head_t poll; 11 12 int event;
+16 -8
fs/namespace.c
··· 12 12 #include <linux/export.h> 13 13 #include <linux/capability.h> 14 14 #include <linux/mnt_namespace.h> 15 + #include <linux/user_namespace.h> 15 16 #include <linux/namei.h> 16 17 #include <linux/security.h> 17 18 #include <linux/idr.h> ··· 2287 2286 return retval; 2288 2287 } 2289 2288 2289 + static void free_mnt_ns(struct mnt_namespace *ns) 2290 + { 2291 + put_user_ns(ns->user_ns); 2292 + kfree(ns); 2293 + } 2294 + 2290 2295 /* 2291 2296 * Assign a sequence number so we can detect when we attempt to bind 2292 2297 * mount a reference to an older mount namespace into the current ··· 2302 2295 */ 2303 2296 static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); 2304 2297 2305 - static struct mnt_namespace *alloc_mnt_ns(void) 2298 + static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) 2306 2299 { 2307 2300 struct mnt_namespace *new_ns; 2308 2301 ··· 2315 2308 INIT_LIST_HEAD(&new_ns->list); 2316 2309 init_waitqueue_head(&new_ns->poll); 2317 2310 new_ns->event = 0; 2311 + new_ns->user_ns = get_user_ns(user_ns); 2318 2312 return new_ns; 2319 2313 } 2320 2314 ··· 2324 2316 * copied from the namespace of the passed in task structure. 2325 2317 */ 2326 2318 static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, 2327 - struct fs_struct *fs) 2319 + struct user_namespace *user_ns, struct fs_struct *fs) 2328 2320 { 2329 2321 struct mnt_namespace *new_ns; 2330 2322 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; ··· 2332 2324 struct mount *old = mnt_ns->root; 2333 2325 struct mount *new; 2334 2326 2335 - new_ns = alloc_mnt_ns(); 2327 + new_ns = alloc_mnt_ns(user_ns); 2336 2328 if (IS_ERR(new_ns)) 2337 2329 return new_ns; 2338 2330 ··· 2341 2333 new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); 2342 2334 if (IS_ERR(new)) { 2343 2335 up_write(&namespace_sem); 2344 - kfree(new_ns); 2336 + free_mnt_ns(new_ns); 2345 2337 return ERR_CAST(new); 2346 2338 } 2347 2339 new_ns->root = new; ··· 2382 2374 } 2383 2375 2384 2376 struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, 2385 - struct fs_struct *new_fs) 2377 + struct user_namespace *user_ns, struct fs_struct *new_fs) 2386 2378 { 2387 2379 struct mnt_namespace *new_ns; 2388 2380 ··· 2392 2384 if (!(flags & CLONE_NEWNS)) 2393 2385 return ns; 2394 2386 2395 - new_ns = dup_mnt_ns(ns, new_fs); 2387 + new_ns = dup_mnt_ns(ns, user_ns, new_fs); 2396 2388 2397 2389 put_mnt_ns(ns); 2398 2390 return new_ns; ··· 2404 2396 */ 2405 2397 static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) 2406 2398 { 2407 - struct mnt_namespace *new_ns = alloc_mnt_ns(); 2399 + struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns); 2408 2400 if (!IS_ERR(new_ns)) { 2409 2401 struct mount *mnt = real_mount(m); 2410 2402 mnt->mnt_ns = new_ns; ··· 2690 2682 br_write_unlock(&vfsmount_lock); 2691 2683 up_write(&namespace_sem); 2692 2684 release_mounts(&umount_list); 2693 - kfree(ns); 2685 + free_mnt_ns(ns); 2694 2686 } 2695 2687 2696 2688 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+2 -1
include/linux/mnt_namespace.h
··· 4 4 5 5 struct mnt_namespace; 6 6 struct fs_struct; 7 + struct user_namespace; 7 8 8 9 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, 9 - struct fs_struct *); 10 + struct user_namespace *, struct fs_struct *); 10 11 extern void put_mnt_ns(struct mnt_namespace *ns); 11 12 12 13 extern const struct file_operations proc_mounts_operations;
+1 -1
kernel/nsproxy.c
··· 66 66 if (!new_nsp) 67 67 return ERR_PTR(-ENOMEM); 68 68 69 - new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs); 69 + new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, task_cred_xxx(tsk, user_ns), new_fs); 70 70 if (IS_ERR(new_nsp->mnt_ns)) { 71 71 err = PTR_ERR(new_nsp->mnt_ns); 72 72 goto out_ns;