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 ns->id = -1; 52 } 53 return ns; 54 } 55 56 /* 57 * copies the nsproxy, setting refcount to 1, and grabbing a 58 * reference to all contained namespaces. Called from 59 * sys_unshare() 60 */ 61 struct nsproxy *dup_namespaces(struct nsproxy *orig) 62 { 63 struct nsproxy *ns = clone_namespaces(orig); 64 65 if (ns) { 66 if (ns->mnt_ns) 67 get_mnt_ns(ns->mnt_ns); 68 if (ns->uts_ns) 69 get_uts_ns(ns->uts_ns); 70 if (ns->ipc_ns) 71 get_ipc_ns(ns->ipc_ns); 72 if (ns->pid_ns) 73 get_pid_ns(ns->pid_ns); 74 } 75 76 return ns; 77 } 78 79 /* 80 * called from clone. This now handles copy for nsproxy and all 81 * namespaces therein. 82 */ 83 int copy_namespaces(int flags, struct task_struct *tsk) 84 { 85 struct nsproxy *old_ns = tsk->nsproxy; 86 struct nsproxy *new_ns; 87 int err = 0; 88 89 if (!old_ns) 90 return 0; 91 92 get_nsproxy(old_ns); 93 94 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) 95 return 0; 96 97 new_ns = clone_namespaces(old_ns); 98 if (!new_ns) { 99 err = -ENOMEM; 100 goto out; 101 } 102 103 tsk->nsproxy = new_ns; 104 105 err = copy_mnt_ns(flags, tsk); 106 if (err) 107 goto out_ns; 108 109 err = copy_utsname(flags, tsk); 110 if (err) 111 goto out_uts; 112 113 err = copy_ipcs(flags, tsk); 114 if (err) 115 goto out_ipc; 116 117 err = copy_pid_ns(flags, tsk); 118 if (err) 119 goto out_pid; 120 121 out: 122 put_nsproxy(old_ns); 123 return err; 124 125 out_pid: 126 if (new_ns->ipc_ns) 127 put_ipc_ns(new_ns->ipc_ns); 128 out_ipc: 129 if (new_ns->uts_ns) 130 put_uts_ns(new_ns->uts_ns); 131 out_uts: 132 if (new_ns->mnt_ns) 133 put_mnt_ns(new_ns->mnt_ns); 134 out_ns: 135 tsk->nsproxy = old_ns; 136 kfree(new_ns); 137 goto out; 138 } 139 140 void free_nsproxy(struct nsproxy *ns) 141 { 142 if (ns->mnt_ns) 143 put_mnt_ns(ns->mnt_ns); 144 if (ns->uts_ns) 145 put_uts_ns(ns->uts_ns); 146 if (ns->ipc_ns) 147 put_ipc_ns(ns->ipc_ns); 148 if (ns->pid_ns) 149 put_pid_ns(ns->pid_ns); 150 kfree(ns); 151 } 152