aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/nsproxy.c
diff options
context:
space:
mode:
authorBadari Pulavarty <pbadari@us.ibm.com>2007-05-08 03:25:21 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:00 -0400
commite3222c4ecc649c4ae568e61dda9349482401b501 (patch)
treed96614ef67d947a3dd8ab0929a4755bce9fdbcc1 /kernel/nsproxy.c
parent4fc75ff4816c3483b4b772b2f6cb3d8fd88ca547 (diff)
Merge sys_clone()/sys_unshare() nsproxy and namespace handling
sys_clone() and sys_unshare() both makes copies of nsproxy and its associated namespaces. But they have different code paths. This patch merges all the nsproxy and its associated namespace copy/clone handling (as much as possible). Posted on container list earlier for feedback. - Create a new nsproxy and its associated namespaces and pass it back to caller to attach it to right process. - Changed all copy_*_ns() routines to return a new copy of namespace instead of attaching it to task->nsproxy. - Moved the CAP_SYS_ADMIN checks out of copy_*_ns() routines. - Removed unnessary !ns checks from copy_*_ns() and added BUG_ON() just incase. - Get rid of all individual unshare_*_ns() routines and make use of copy_*_ns() instead. [akpm@osdl.org: cleanups, warning fix] [clg@fr.ibm.com: remove dup_namespaces() declaration] [serue@us.ibm.com: fix CONFIG_IPC_NS=n, clone(CLONE_NEWIPC) retval] [akpm@linux-foundation.org: fix build with CONFIG_SYSVIPC=n] Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com> Signed-off-by: Serge Hallyn <serue@us.ibm.com> Cc: Cedric Le Goater <clg@fr.ibm.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: <containers@lists.osdl.org> Signed-off-by: Cedric Le Goater <clg@fr.ibm.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/nsproxy.c')
-rw-r--r--kernel/nsproxy.c139
1 files changed, 86 insertions, 53 deletions
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index f5b9ee6f6bbb..1bc4b55241a8 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -38,10 +38,8 @@ void get_task_namespaces(struct task_struct *tsk)
38 38
39/* 39/*
40 * creates a copy of "orig" with refcount 1. 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 */ 41 */
44static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) 42static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig)
45{ 43{
46 struct nsproxy *ns; 44 struct nsproxy *ns;
47 45
@@ -52,26 +50,49 @@ static inline struct nsproxy *clone_namespaces(struct nsproxy *orig)
52} 50}
53 51
54/* 52/*
55 * copies the nsproxy, setting refcount to 1, and grabbing a 53 * Create new nsproxy and all of its the associated namespaces.
56 * reference to all contained namespaces. Called from 54 * Return the newly created nsproxy. Do not attach this to the task,
57 * sys_unshare() 55 * leave it to the caller to do proper locking and attach it to task.
58 */ 56 */
59struct nsproxy *dup_namespaces(struct nsproxy *orig) 57static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk,
58 struct fs_struct *new_fs)
60{ 59{
61 struct nsproxy *ns = clone_namespaces(orig); 60 struct nsproxy *new_nsp;
62 61
63 if (ns) { 62 new_nsp = clone_nsproxy(tsk->nsproxy);
64 if (ns->mnt_ns) 63 if (!new_nsp)
65 get_mnt_ns(ns->mnt_ns); 64 return ERR_PTR(-ENOMEM);
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 65
74 return ns; 66 new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs);
67 if (IS_ERR(new_nsp->mnt_ns))
68 goto out_ns;
69
70 new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns);
71 if (IS_ERR(new_nsp->uts_ns))
72 goto out_uts;
73
74 new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
75 if (IS_ERR(new_nsp->ipc_ns))
76 goto out_ipc;
77
78 new_nsp->pid_ns = copy_pid_ns(flags, tsk->nsproxy->pid_ns);
79 if (IS_ERR(new_nsp->pid_ns))
80 goto out_pid;
81
82 return new_nsp;
83
84out_pid:
85 if (new_nsp->ipc_ns)
86 put_ipc_ns(new_nsp->ipc_ns);
87out_ipc:
88 if (new_nsp->uts_ns)
89 put_uts_ns(new_nsp->uts_ns);
90out_uts:
91 if (new_nsp->mnt_ns)
92 put_mnt_ns(new_nsp->mnt_ns);
93out_ns:
94 kfree(new_nsp);
95 return ERR_PTR(-ENOMEM);
75} 96}
76 97
77/* 98/*
@@ -92,47 +113,21 @@ int copy_namespaces(int flags, struct task_struct *tsk)
92 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) 113 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
93 return 0; 114 return 0;
94 115
95 new_ns = clone_namespaces(old_ns); 116 if (!capable(CAP_SYS_ADMIN)) {
96 if (!new_ns) { 117 err = -EPERM;
97 err = -ENOMEM;
98 goto out; 118 goto out;
99 } 119 }
100 120
101 tsk->nsproxy = new_ns; 121 new_ns = create_new_namespaces(flags, tsk, tsk->fs);
102 122 if (IS_ERR(new_ns)) {
103 err = copy_mnt_ns(flags, tsk); 123 err = PTR_ERR(new_ns);
104 if (err) 124 goto out;
105 goto out_ns; 125 }
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 126
127 tsk->nsproxy = new_ns;
119out: 128out:
120 put_nsproxy(old_ns); 129 put_nsproxy(old_ns);
121 return err; 130 return err;
122
123out_pid:
124 if (new_ns->ipc_ns)
125 put_ipc_ns(new_ns->ipc_ns);
126out_ipc:
127 if (new_ns->uts_ns)
128 put_uts_ns(new_ns->uts_ns);
129out_uts:
130 if (new_ns->mnt_ns)
131 put_mnt_ns(new_ns->mnt_ns);
132out_ns:
133 tsk->nsproxy = old_ns;
134 kfree(new_ns);
135 goto out;
136} 131}
137 132
138void free_nsproxy(struct nsproxy *ns) 133void free_nsproxy(struct nsproxy *ns)
@@ -147,3 +142,41 @@ void free_nsproxy(struct nsproxy *ns)
147 put_pid_ns(ns->pid_ns); 142 put_pid_ns(ns->pid_ns);
148 kfree(ns); 143 kfree(ns);
149} 144}
145
146/*
147 * Called from unshare. Unshare all the namespaces part of nsproxy.
148 * On sucess, returns the new nsproxy and a reference to old nsproxy
149 * to make sure it stays around.
150 */
151int unshare_nsproxy_namespaces(unsigned long unshare_flags,
152 struct nsproxy **new_nsp, struct fs_struct *new_fs)
153{
154 struct nsproxy *old_ns = current->nsproxy;
155 int err = 0;
156
157 if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
158 return 0;
159
160#ifndef CONFIG_IPC_NS
161 if (unshare_flags & CLONE_NEWIPC)
162 return -EINVAL;
163#endif
164
165#ifndef CONFIG_UTS_NS
166 if (unshare_flags & CLONE_NEWUTS)
167 return -EINVAL;
168#endif
169
170 if (!capable(CAP_SYS_ADMIN))
171 return -EPERM;
172
173 get_nsproxy(old_ns);
174
175 *new_nsp = create_new_namespaces(unshare_flags, current,
176 new_fs ? new_fs : current->fs);
177 if (IS_ERR(*new_nsp)) {
178 err = PTR_ERR(*new_nsp);
179 put_nsproxy(old_ns);
180 }
181 return err;
182}