diff options
Diffstat (limited to 'kernel/nsproxy.c')
-rw-r--r-- | kernel/nsproxy.c | 36 |
1 files changed, 19 insertions, 17 deletions
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index b576f7f14bc6..78e2ecb20165 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -57,7 +57,8 @@ static inline struct nsproxy *create_nsproxy(void) | |||
57 | * leave it to the caller to do proper locking and attach it to task. | 57 | * leave it to the caller to do proper locking and attach it to task. |
58 | */ | 58 | */ |
59 | static struct nsproxy *create_new_namespaces(unsigned long flags, | 59 | static struct nsproxy *create_new_namespaces(unsigned long flags, |
60 | struct task_struct *tsk, struct fs_struct *new_fs) | 60 | struct task_struct *tsk, struct user_namespace *user_ns, |
61 | struct fs_struct *new_fs) | ||
61 | { | 62 | { |
62 | struct nsproxy *new_nsp; | 63 | struct nsproxy *new_nsp; |
63 | int err; | 64 | int err; |
@@ -66,31 +67,31 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, | |||
66 | if (!new_nsp) | 67 | if (!new_nsp) |
67 | return ERR_PTR(-ENOMEM); | 68 | return ERR_PTR(-ENOMEM); |
68 | 69 | ||
69 | new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs); | 70 | new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs); |
70 | if (IS_ERR(new_nsp->mnt_ns)) { | 71 | if (IS_ERR(new_nsp->mnt_ns)) { |
71 | err = PTR_ERR(new_nsp->mnt_ns); | 72 | err = PTR_ERR(new_nsp->mnt_ns); |
72 | goto out_ns; | 73 | goto out_ns; |
73 | } | 74 | } |
74 | 75 | ||
75 | new_nsp->uts_ns = copy_utsname(flags, tsk); | 76 | new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns); |
76 | if (IS_ERR(new_nsp->uts_ns)) { | 77 | if (IS_ERR(new_nsp->uts_ns)) { |
77 | err = PTR_ERR(new_nsp->uts_ns); | 78 | err = PTR_ERR(new_nsp->uts_ns); |
78 | goto out_uts; | 79 | goto out_uts; |
79 | } | 80 | } |
80 | 81 | ||
81 | new_nsp->ipc_ns = copy_ipcs(flags, tsk); | 82 | new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns); |
82 | if (IS_ERR(new_nsp->ipc_ns)) { | 83 | if (IS_ERR(new_nsp->ipc_ns)) { |
83 | err = PTR_ERR(new_nsp->ipc_ns); | 84 | err = PTR_ERR(new_nsp->ipc_ns); |
84 | goto out_ipc; | 85 | goto out_ipc; |
85 | } | 86 | } |
86 | 87 | ||
87 | new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); | 88 | new_nsp->pid_ns = copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns); |
88 | if (IS_ERR(new_nsp->pid_ns)) { | 89 | if (IS_ERR(new_nsp->pid_ns)) { |
89 | err = PTR_ERR(new_nsp->pid_ns); | 90 | err = PTR_ERR(new_nsp->pid_ns); |
90 | goto out_pid; | 91 | goto out_pid; |
91 | } | 92 | } |
92 | 93 | ||
93 | new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns); | 94 | new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns); |
94 | if (IS_ERR(new_nsp->net_ns)) { | 95 | if (IS_ERR(new_nsp->net_ns)) { |
95 | err = PTR_ERR(new_nsp->net_ns); | 96 | err = PTR_ERR(new_nsp->net_ns); |
96 | goto out_net; | 97 | goto out_net; |
@@ -122,6 +123,7 @@ out_ns: | |||
122 | int copy_namespaces(unsigned long flags, struct task_struct *tsk) | 123 | int copy_namespaces(unsigned long flags, struct task_struct *tsk) |
123 | { | 124 | { |
124 | struct nsproxy *old_ns = tsk->nsproxy; | 125 | struct nsproxy *old_ns = tsk->nsproxy; |
126 | struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); | ||
125 | struct nsproxy *new_ns; | 127 | struct nsproxy *new_ns; |
126 | int err = 0; | 128 | int err = 0; |
127 | 129 | ||
@@ -134,7 +136,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
134 | CLONE_NEWPID | CLONE_NEWNET))) | 136 | CLONE_NEWPID | CLONE_NEWNET))) |
135 | return 0; | 137 | return 0; |
136 | 138 | ||
137 | if (!capable(CAP_SYS_ADMIN)) { | 139 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) { |
138 | err = -EPERM; | 140 | err = -EPERM; |
139 | goto out; | 141 | goto out; |
140 | } | 142 | } |
@@ -151,7 +153,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
151 | goto out; | 153 | goto out; |
152 | } | 154 | } |
153 | 155 | ||
154 | new_ns = create_new_namespaces(flags, tsk, tsk->fs); | 156 | new_ns = create_new_namespaces(flags, tsk, |
157 | task_cred_xxx(tsk, user_ns), tsk->fs); | ||
155 | if (IS_ERR(new_ns)) { | 158 | if (IS_ERR(new_ns)) { |
156 | err = PTR_ERR(new_ns); | 159 | err = PTR_ERR(new_ns); |
157 | goto out; | 160 | goto out; |
@@ -183,19 +186,21 @@ void free_nsproxy(struct nsproxy *ns) | |||
183 | * On success, returns the new nsproxy. | 186 | * On success, returns the new nsproxy. |
184 | */ | 187 | */ |
185 | int unshare_nsproxy_namespaces(unsigned long unshare_flags, | 188 | int unshare_nsproxy_namespaces(unsigned long unshare_flags, |
186 | struct nsproxy **new_nsp, struct fs_struct *new_fs) | 189 | struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs) |
187 | { | 190 | { |
191 | struct user_namespace *user_ns; | ||
188 | int err = 0; | 192 | int err = 0; |
189 | 193 | ||
190 | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | | 194 | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | |
191 | CLONE_NEWNET))) | 195 | CLONE_NEWNET | CLONE_NEWPID))) |
192 | return 0; | 196 | return 0; |
193 | 197 | ||
194 | if (!capable(CAP_SYS_ADMIN)) | 198 | user_ns = new_cred ? new_cred->user_ns : current_user_ns(); |
199 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
195 | return -EPERM; | 200 | return -EPERM; |
196 | 201 | ||
197 | *new_nsp = create_new_namespaces(unshare_flags, current, | 202 | *new_nsp = create_new_namespaces(unshare_flags, current, user_ns, |
198 | new_fs ? new_fs : current->fs); | 203 | new_fs ? new_fs : current->fs); |
199 | if (IS_ERR(*new_nsp)) { | 204 | if (IS_ERR(*new_nsp)) { |
200 | err = PTR_ERR(*new_nsp); | 205 | err = PTR_ERR(*new_nsp); |
201 | goto out; | 206 | goto out; |
@@ -241,9 +246,6 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) | |||
241 | struct file *file; | 246 | struct file *file; |
242 | int err; | 247 | int err; |
243 | 248 | ||
244 | if (!capable(CAP_SYS_ADMIN)) | ||
245 | return -EPERM; | ||
246 | |||
247 | file = proc_ns_fget(fd); | 249 | file = proc_ns_fget(fd); |
248 | if (IS_ERR(file)) | 250 | if (IS_ERR(file)) |
249 | return PTR_ERR(file); | 251 | return PTR_ERR(file); |
@@ -254,7 +256,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) | |||
254 | if (nstype && (ops->type != nstype)) | 256 | if (nstype && (ops->type != nstype)) |
255 | goto out; | 257 | goto out; |
256 | 258 | ||
257 | new_nsproxy = create_new_namespaces(0, tsk, tsk->fs); | 259 | new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs); |
258 | if (IS_ERR(new_nsproxy)) { | 260 | if (IS_ERR(new_nsproxy)) { |
259 | err = PTR_ERR(new_nsproxy); | 261 | err = PTR_ERR(new_nsproxy); |
260 | goto out; | 262 | goto out; |