diff options
author | Badari Pulavarty <pbadari@us.ibm.com> | 2007-05-08 03:25:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:15:00 -0400 |
commit | e3222c4ecc649c4ae568e61dda9349482401b501 (patch) | |
tree | d96614ef67d947a3dd8ab0929a4755bce9fdbcc1 /kernel/nsproxy.c | |
parent | 4fc75ff4816c3483b4b772b2f6cb3d8fd88ca547 (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.c | 139 |
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 | */ |
44 | static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) | 42 | static 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 | */ |
59 | struct nsproxy *dup_namespaces(struct nsproxy *orig) | 57 | static 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 | |||
84 | out_pid: | ||
85 | if (new_nsp->ipc_ns) | ||
86 | put_ipc_ns(new_nsp->ipc_ns); | ||
87 | out_ipc: | ||
88 | if (new_nsp->uts_ns) | ||
89 | put_uts_ns(new_nsp->uts_ns); | ||
90 | out_uts: | ||
91 | if (new_nsp->mnt_ns) | ||
92 | put_mnt_ns(new_nsp->mnt_ns); | ||
93 | out_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; | ||
119 | out: | 128 | out: |
120 | put_nsproxy(old_ns); | 129 | put_nsproxy(old_ns); |
121 | return err; | 130 | 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 | } | 131 | } |
137 | 132 | ||
138 | void free_nsproxy(struct nsproxy *ns) | 133 | void 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 | */ | ||
151 | int 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 | } | ||