Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * Copyright (C) 2006 IBM Corporation 4 : : * 5 : : * Author: Serge Hallyn <serue@us.ibm.com> 6 : : * 7 : : * Jun 2006 - namespaces support 8 : : * OpenVZ, SWsoft Inc. 9 : : * Pavel Emelianov <xemul@openvz.org> 10 : : */ 11 : : 12 : : #include <linux/slab.h> 13 : : #include <linux/export.h> 14 : : #include <linux/nsproxy.h> 15 : : #include <linux/init_task.h> 16 : : #include <linux/mnt_namespace.h> 17 : : #include <linux/utsname.h> 18 : : #include <linux/pid_namespace.h> 19 : : #include <net/net_namespace.h> 20 : : #include <linux/ipc_namespace.h> 21 : : #include <linux/proc_ns.h> 22 : : #include <linux/file.h> 23 : : #include <linux/syscalls.h> 24 : : #include <linux/cgroup.h> 25 : : #include <linux/perf_event.h> 26 : : 27 : : static struct kmem_cache *nsproxy_cachep; 28 : : 29 : : struct nsproxy init_nsproxy = { 30 : : .count = ATOMIC_INIT(1), 31 : : .uts_ns = &init_uts_ns, 32 : : #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) 33 : : .ipc_ns = &init_ipc_ns, 34 : : #endif 35 : : .mnt_ns = NULL, 36 : : .pid_ns_for_children = &init_pid_ns, 37 : : #ifdef CONFIG_NET 38 : : .net_ns = &init_net, 39 : : #endif 40 : : #ifdef CONFIG_CGROUPS 41 : : .cgroup_ns = &init_cgroup_ns, 42 : : #endif 43 : : }; 44 : : 45 : 3 : static inline struct nsproxy *create_nsproxy(void) 46 : : { 47 : : struct nsproxy *nsproxy; 48 : : 49 : 3 : nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL); 50 : 3 : if (nsproxy) 51 : : atomic_set(&nsproxy->count, 1); 52 : 3 : return nsproxy; 53 : : } 54 : : 55 : : /* 56 : : * Create new nsproxy and all of its the associated namespaces. 57 : : * Return the newly created nsproxy. Do not attach this to the task, 58 : : * leave it to the caller to do proper locking and attach it to task. 59 : : */ 60 : 3 : static struct nsproxy *create_new_namespaces(unsigned long flags, 61 : : struct task_struct *tsk, struct user_namespace *user_ns, 62 : : struct fs_struct *new_fs) 63 : : { 64 : : struct nsproxy *new_nsp; 65 : : int err; 66 : : 67 : 3 : new_nsp = create_nsproxy(); 68 : 3 : if (!new_nsp) 69 : : return ERR_PTR(-ENOMEM); 70 : : 71 : 3 : new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs); 72 : 3 : if (IS_ERR(new_nsp->mnt_ns)) { 73 : : err = PTR_ERR(new_nsp->mnt_ns); 74 : 0 : goto out_ns; 75 : : } 76 : : 77 : 3 : new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns); 78 : 3 : if (IS_ERR(new_nsp->uts_ns)) { 79 : : err = PTR_ERR(new_nsp->uts_ns); 80 : 0 : goto out_uts; 81 : : } 82 : : 83 : 3 : new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns); 84 : 3 : if (IS_ERR(new_nsp->ipc_ns)) { 85 : : err = PTR_ERR(new_nsp->ipc_ns); 86 : 0 : goto out_ipc; 87 : : } 88 : : 89 : 3 : new_nsp->pid_ns_for_children = 90 : 3 : copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children); 91 : 3 : if (IS_ERR(new_nsp->pid_ns_for_children)) { 92 : : err = PTR_ERR(new_nsp->pid_ns_for_children); 93 : 0 : goto out_pid; 94 : : } 95 : : 96 : 3 : new_nsp->cgroup_ns = copy_cgroup_ns(flags, user_ns, 97 : 3 : tsk->nsproxy->cgroup_ns); 98 : 3 : if (IS_ERR(new_nsp->cgroup_ns)) { 99 : : err = PTR_ERR(new_nsp->cgroup_ns); 100 : 0 : goto out_cgroup; 101 : : } 102 : : 103 : 3 : new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns); 104 : 3 : if (IS_ERR(new_nsp->net_ns)) { 105 : : err = PTR_ERR(new_nsp->net_ns); 106 : : goto out_net; 107 : : } 108 : : 109 : : return new_nsp; 110 : : 111 : : out_net: 112 : 0 : put_cgroup_ns(new_nsp->cgroup_ns); 113 : : out_cgroup: 114 : 0 : if (new_nsp->pid_ns_for_children) 115 : 0 : put_pid_ns(new_nsp->pid_ns_for_children); 116 : : out_pid: 117 : 0 : if (new_nsp->ipc_ns) 118 : 0 : put_ipc_ns(new_nsp->ipc_ns); 119 : : out_ipc: 120 : 0 : if (new_nsp->uts_ns) 121 : : put_uts_ns(new_nsp->uts_ns); 122 : : out_uts: 123 : 0 : if (new_nsp->mnt_ns) 124 : 0 : put_mnt_ns(new_nsp->mnt_ns); 125 : : out_ns: 126 : 0 : kmem_cache_free(nsproxy_cachep, new_nsp); 127 : 0 : return ERR_PTR(err); 128 : : } 129 : : 130 : : /* 131 : : * called from clone. This now handles copy for nsproxy and all 132 : : * namespaces therein. 133 : : */ 134 : 3 : int copy_namespaces(unsigned long flags, struct task_struct *tsk) 135 : : { 136 : 3 : struct nsproxy *old_ns = tsk->nsproxy; 137 : 3 : struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); 138 : : struct nsproxy *new_ns; 139 : : 140 : 3 : if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | 141 : : CLONE_NEWPID | CLONE_NEWNET | 142 : : CLONE_NEWCGROUP)))) { 143 : : get_nsproxy(old_ns); 144 : 3 : return 0; 145 : : } 146 : : 147 : 0 : if (!ns_capable(user_ns, CAP_SYS_ADMIN)) 148 : : return -EPERM; 149 : : 150 : : /* 151 : : * CLONE_NEWIPC must detach from the undolist: after switching 152 : : * to a new ipc namespace, the semaphore arrays from the old 153 : : * namespace are unreachable. In clone parlance, CLONE_SYSVSEM 154 : : * means share undolist with parent, so we must forbid using 155 : : * it along with CLONE_NEWIPC. 156 : : */ 157 : 0 : if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) == 158 : : (CLONE_NEWIPC | CLONE_SYSVSEM)) 159 : : return -EINVAL; 160 : : 161 : 0 : new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); 162 : 0 : if (IS_ERR(new_ns)) 163 : 0 : return PTR_ERR(new_ns); 164 : : 165 : 0 : tsk->nsproxy = new_ns; 166 : 0 : return 0; 167 : : } 168 : : 169 : 2 : void free_nsproxy(struct nsproxy *ns) 170 : : { 171 : 2 : if (ns->mnt_ns) 172 : 2 : put_mnt_ns(ns->mnt_ns); 173 : 2 : if (ns->uts_ns) 174 : : put_uts_ns(ns->uts_ns); 175 : 2 : if (ns->ipc_ns) 176 : 2 : put_ipc_ns(ns->ipc_ns); 177 : 2 : if (ns->pid_ns_for_children) 178 : 2 : put_pid_ns(ns->pid_ns_for_children); 179 : 2 : put_cgroup_ns(ns->cgroup_ns); 180 : 2 : put_net(ns->net_ns); 181 : 2 : kmem_cache_free(nsproxy_cachep, ns); 182 : 2 : } 183 : : 184 : : /* 185 : : * Called from unshare. Unshare all the namespaces part of nsproxy. 186 : : * On success, returns the new nsproxy. 187 : : */ 188 : 3 : int unshare_nsproxy_namespaces(unsigned long unshare_flags, 189 : : struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs) 190 : : { 191 : : struct user_namespace *user_ns; 192 : : int err = 0; 193 : : 194 : 3 : if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | 195 : : CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP))) 196 : : return 0; 197 : : 198 : 3 : user_ns = new_cred ? new_cred->user_ns : current_user_ns(); 199 : 3 : if (!ns_capable(user_ns, CAP_SYS_ADMIN)) 200 : : return -EPERM; 201 : : 202 : 3 : *new_nsp = create_new_namespaces(unshare_flags, current, user_ns, 203 : : new_fs ? new_fs : current->fs); 204 : 3 : if (IS_ERR(*new_nsp)) { 205 : : err = PTR_ERR(*new_nsp); 206 : 0 : goto out; 207 : : } 208 : : 209 : : out: 210 : 3 : return err; 211 : : } 212 : : 213 : 3 : void switch_task_namespaces(struct task_struct *p, struct nsproxy *new) 214 : : { 215 : : struct nsproxy *ns; 216 : : 217 : 3 : might_sleep(); 218 : : 219 : : task_lock(p); 220 : 3 : ns = p->nsproxy; 221 : 3 : p->nsproxy = new; 222 : : task_unlock(p); 223 : : 224 : 3 : if (ns && atomic_dec_and_test(&ns->count)) 225 : 2 : free_nsproxy(ns); 226 : 3 : } 227 : : 228 : 3 : void exit_task_namespaces(struct task_struct *p) 229 : : { 230 : 3 : switch_task_namespaces(p, NULL); 231 : 3 : } 232 : : 233 : 0 : SYSCALL_DEFINE2(setns, int, fd, int, nstype) 234 : : { 235 : 0 : struct task_struct *tsk = current; 236 : : struct nsproxy *new_nsproxy; 237 : : struct file *file; 238 : : struct ns_common *ns; 239 : : int err; 240 : : 241 : 0 : file = proc_ns_fget(fd); 242 : 0 : if (IS_ERR(file)) 243 : 0 : return PTR_ERR(file); 244 : : 245 : : err = -EINVAL; 246 : 0 : ns = get_proc_ns(file_inode(file)); 247 : 0 : if (nstype && (ns->ops->type != nstype)) 248 : : goto out; 249 : : 250 : 0 : new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs); 251 : 0 : if (IS_ERR(new_nsproxy)) { 252 : : err = PTR_ERR(new_nsproxy); 253 : 0 : goto out; 254 : : } 255 : : 256 : 0 : err = ns->ops->install(new_nsproxy, ns); 257 : 0 : if (err) { 258 : 0 : free_nsproxy(new_nsproxy); 259 : 0 : goto out; 260 : : } 261 : 0 : switch_task_namespaces(tsk, new_nsproxy); 262 : : 263 : 0 : perf_event_namespaces(tsk); 264 : : out: 265 : 0 : fput(file); 266 : 0 : return err; 267 : : } 268 : : 269 : 3 : int __init nsproxy_cache_init(void) 270 : : { 271 : 3 : nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC); 272 : 3 : return 0; 273 : : }