1 /* 2 * Copyright (C) 2006 IBM Corporation 3 * 4 * Author: Serge Hallyn <serue@us.ibm.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation, version 2 of the 9 * License. 10 * 11 * Jun 2006 - namespaces support 12 * OpenVZ, SWsoft Inc. 13 * Pavel Emelianov <xemul@openvz.org> 14 */ 15 16 #include <linux/module.h> 17 #include <linux/version.h> 18 #include <linux/nsproxy.h> 19 #include <linux/init_task.h> 20 #include <linux/mnt_namespace.h> 21 #include <linux/utsname.h> 22 #include <linux/pid_namespace.h> 23 24 struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); 25 26 static inline void get_nsproxy(struct nsproxy *ns) 27 { 28 atomic_inc(&ns->count); 29 } 30 31 void get_task_namespaces(struct task_struct *tsk) 32 { 33 struct nsproxy *ns = tsk->nsproxy; 34 if (ns) { 35 get_nsproxy(ns); 36 } 37 } 38 39 /* 40 * creates a copy of "orig" with refcount 1. 41 * This does not grab references to the contained namespaces, 42 * so that needs to be done by dup_namespaces. 43 */ 44 static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) 45 { 46 struct nsproxy *ns; 47 48 ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL); 49 if (ns) 50 atomic_set(&ns->count, 1); 51 return ns; 52 } 53 54 /* 55 * copies the nsproxy, setting refcount to 1, and grabbing a 56 * reference to all contained namespaces. Called from 57 * sys_unshare() 58 */ 59 struct nsproxy *dup_namespaces(struct nsproxy *orig) 60 { 61 struct nsproxy *ns = clone_namespaces(orig); 62 63 if (ns) { 64 if (ns->mnt_ns) 65 get_mnt_ns(ns->mnt_ns); 66 if (ns->uts_ns) 67 get_uts_ns(ns->uts_ns); 68 if (ns->ipc_ns) 69 get_ipc_ns(ns->ipc_ns); 70 if (ns->pid_ns) 71 get_pid_ns(ns->pid_ns); 72 } 73 74 return ns; 75 } 76 77 /* 78 * called from clone. This now handles copy for nsproxy and all 79 * namespaces therein. 80 */ 81 int copy_namespaces(int flags, struct task_struct *tsk) 82 { 83 struct nsproxy *old_ns = tsk->nsproxy; 84 struct nsproxy *new_ns; 85 int err = 0; 86 87 if (!old_ns) 88 return 0; 89 90 get_nsproxy(old_ns); 91 92 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) 93 return 0; 94 95 new_ns = clone_namespaces(old_ns); 96 if (!new_ns) { 97 err = -ENOMEM; 98 goto out; 99 } 100 101 tsk->nsproxy = new_ns; 102 103 err = copy_mnt_ns(flags, tsk); 104 if (err) 105 goto out_ns; 106 107 err = copy_utsname(flags, tsk); 108 if (err) 109 goto out_uts; 110 111 err = copy_ipcs(flags, tsk); 112 if (err) 113 goto out_ipc; 114 115 err = copy_pid_ns(flags, tsk); 116 if (err) 117 goto out_pid; 118 119 out: 120 put_nsproxy(old_ns); 121 return err; 122 123 out_pid: 124 if (new_ns->ipc_ns) 125 put_ipc_ns(new_ns->ipc_ns); 126 out_ipc: 127 if (new_ns->uts_ns) 128 put_uts_ns(new_ns->uts_ns); 129 out_uts: 130 if (new_ns->mnt_ns) 131 put_mnt_ns(new_ns->mnt_ns); 132 out_ns: 133 tsk->nsproxy = old_ns; 134 kfree(new_ns); 135 goto out; 136 } 137 138 void free_nsproxy(struct nsproxy *ns) 139 { 140 if (ns->mnt_ns) 141 put_mnt_ns(ns->mnt_ns); 142 if (ns->uts_ns) 143 put_uts_ns(ns->uts_ns); 144 if (ns->ipc_ns) 145 put_ipc_ns(ns->ipc_ns); 146 if (ns->pid_ns) 147 put_pid_ns(ns->pid_ns); 148 kfree(ns); 149 } 150