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 f5b9ee6f6b..1bc4b55241 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 | } | ||
