diff options
Diffstat (limited to 'kernel/capability.c')
-rw-r--r-- | kernel/capability.c | 227 |
1 files changed, 23 insertions, 204 deletions
diff --git a/kernel/capability.c b/kernel/capability.c index adb262f83de1..58b00519624a 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -127,160 +127,6 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy) | |||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | #ifndef CONFIG_SECURITY_FILE_CAPABILITIES | ||
131 | |||
132 | /* | ||
133 | * Without filesystem capability support, we nominally support one process | ||
134 | * setting the capabilities of another | ||
135 | */ | ||
136 | static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | ||
137 | kernel_cap_t *pIp, kernel_cap_t *pPp) | ||
138 | { | ||
139 | struct task_struct *target; | ||
140 | int ret; | ||
141 | |||
142 | spin_lock(&task_capability_lock); | ||
143 | read_lock(&tasklist_lock); | ||
144 | |||
145 | if (pid && pid != task_pid_vnr(current)) { | ||
146 | target = find_task_by_vpid(pid); | ||
147 | if (!target) { | ||
148 | ret = -ESRCH; | ||
149 | goto out; | ||
150 | } | ||
151 | } else | ||
152 | target = current; | ||
153 | |||
154 | ret = security_capget(target, pEp, pIp, pPp); | ||
155 | |||
156 | out: | ||
157 | read_unlock(&tasklist_lock); | ||
158 | spin_unlock(&task_capability_lock); | ||
159 | |||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * cap_set_pg - set capabilities for all processes in a given process | ||
165 | * group. We call this holding task_capability_lock and tasklist_lock. | ||
166 | */ | ||
167 | static inline int cap_set_pg(int pgrp_nr, kernel_cap_t *effective, | ||
168 | kernel_cap_t *inheritable, | ||
169 | kernel_cap_t *permitted) | ||
170 | { | ||
171 | struct task_struct *g, *target; | ||
172 | int ret = -EPERM; | ||
173 | int found = 0; | ||
174 | struct pid *pgrp; | ||
175 | |||
176 | spin_lock(&task_capability_lock); | ||
177 | read_lock(&tasklist_lock); | ||
178 | |||
179 | pgrp = find_vpid(pgrp_nr); | ||
180 | do_each_pid_task(pgrp, PIDTYPE_PGID, g) { | ||
181 | target = g; | ||
182 | while_each_thread(g, target) { | ||
183 | if (!security_capset_check(target, effective, | ||
184 | inheritable, permitted)) { | ||
185 | security_capset_set(target, effective, | ||
186 | inheritable, permitted); | ||
187 | ret = 0; | ||
188 | } | ||
189 | found = 1; | ||
190 | } | ||
191 | } while_each_pid_task(pgrp, PIDTYPE_PGID, g); | ||
192 | |||
193 | read_unlock(&tasklist_lock); | ||
194 | spin_unlock(&task_capability_lock); | ||
195 | |||
196 | if (!found) | ||
197 | ret = 0; | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * cap_set_all - set capabilities for all processes other than init | ||
203 | * and self. We call this holding task_capability_lock and tasklist_lock. | ||
204 | */ | ||
205 | static inline int cap_set_all(kernel_cap_t *effective, | ||
206 | kernel_cap_t *inheritable, | ||
207 | kernel_cap_t *permitted) | ||
208 | { | ||
209 | struct task_struct *g, *target; | ||
210 | int ret = -EPERM; | ||
211 | int found = 0; | ||
212 | |||
213 | spin_lock(&task_capability_lock); | ||
214 | read_lock(&tasklist_lock); | ||
215 | |||
216 | do_each_thread(g, target) { | ||
217 | if (target == current | ||
218 | || is_container_init(target->group_leader)) | ||
219 | continue; | ||
220 | found = 1; | ||
221 | if (security_capset_check(target, effective, inheritable, | ||
222 | permitted)) | ||
223 | continue; | ||
224 | ret = 0; | ||
225 | security_capset_set(target, effective, inheritable, permitted); | ||
226 | } while_each_thread(g, target); | ||
227 | |||
228 | read_unlock(&tasklist_lock); | ||
229 | spin_unlock(&task_capability_lock); | ||
230 | |||
231 | if (!found) | ||
232 | ret = 0; | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Given the target pid does not refer to the current process we | ||
239 | * need more elaborate support... (This support is not present when | ||
240 | * filesystem capabilities are configured.) | ||
241 | */ | ||
242 | static inline int do_sys_capset_other_tasks(pid_t pid, kernel_cap_t *effective, | ||
243 | kernel_cap_t *inheritable, | ||
244 | kernel_cap_t *permitted) | ||
245 | { | ||
246 | struct task_struct *target; | ||
247 | int ret; | ||
248 | |||
249 | if (!capable(CAP_SETPCAP)) | ||
250 | return -EPERM; | ||
251 | |||
252 | if (pid == -1) /* all procs other than current and init */ | ||
253 | return cap_set_all(effective, inheritable, permitted); | ||
254 | |||
255 | else if (pid < 0) /* all procs in process group */ | ||
256 | return cap_set_pg(-pid, effective, inheritable, permitted); | ||
257 | |||
258 | /* target != current */ | ||
259 | spin_lock(&task_capability_lock); | ||
260 | read_lock(&tasklist_lock); | ||
261 | |||
262 | target = find_task_by_vpid(pid); | ||
263 | if (!target) | ||
264 | ret = -ESRCH; | ||
265 | else { | ||
266 | ret = security_capset_check(target, effective, inheritable, | ||
267 | permitted); | ||
268 | |||
269 | /* having verified that the proposed changes are legal, | ||
270 | we now put them into effect. */ | ||
271 | if (!ret) | ||
272 | security_capset_set(target, effective, inheritable, | ||
273 | permitted); | ||
274 | } | ||
275 | |||
276 | read_unlock(&tasklist_lock); | ||
277 | spin_unlock(&task_capability_lock); | ||
278 | |||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | #else /* ie., def CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
283 | |||
284 | /* | 130 | /* |
285 | * If we have configured with filesystem capability support, then the | 131 | * If we have configured with filesystem capability support, then the |
286 | * only thing that can change the capabilities of the current process | 132 | * only thing that can change the capabilities of the current process |
@@ -315,22 +161,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
315 | } | 161 | } |
316 | 162 | ||
317 | /* | 163 | /* |
318 | * With filesystem capability support configured, the kernel does not | ||
319 | * permit the changing of capabilities in one process by another | ||
320 | * process. (CAP_SETPCAP has much less broad semantics when configured | ||
321 | * this way.) | ||
322 | */ | ||
323 | static inline int do_sys_capset_other_tasks(pid_t pid, | ||
324 | kernel_cap_t *effective, | ||
325 | kernel_cap_t *inheritable, | ||
326 | kernel_cap_t *permitted) | ||
327 | { | ||
328 | return -EPERM; | ||
329 | } | ||
330 | |||
331 | #endif /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
332 | |||
333 | /* | ||
334 | * Atomically modify the effective capabilities returning the original | 164 | * Atomically modify the effective capabilities returning the original |
335 | * value. No permission check is performed here - it is assumed that the | 165 | * value. No permission check is performed here - it is assumed that the |
336 | * caller is permitted to set the desired effective capabilities. | 166 | * caller is permitted to set the desired effective capabilities. |
@@ -424,16 +254,14 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) | |||
424 | * @data: pointer to struct that contains the effective, permitted, | 254 | * @data: pointer to struct that contains the effective, permitted, |
425 | * and inheritable capabilities | 255 | * and inheritable capabilities |
426 | * | 256 | * |
427 | * Set capabilities for a given process, all processes, or all | 257 | * Set capabilities for the current process only. The ability to any other |
428 | * processes in a given process group. | 258 | * process(es) has been deprecated and removed. |
429 | * | 259 | * |
430 | * The restrictions on setting capabilities are specified as: | 260 | * The restrictions on setting capabilities are specified as: |
431 | * | 261 | * |
432 | * [pid is for the 'target' task. 'current' is the calling task.] | 262 | * I: any raised capabilities must be a subset of the old permitted |
433 | * | 263 | * P: any raised capabilities must be a subset of the old permitted |
434 | * I: any raised capabilities must be a subset of the (old current) permitted | 264 | * E: must be set to a subset of new permitted |
435 | * P: any raised capabilities must be a subset of the (old current) permitted | ||
436 | * E: must be set to a subset of (new target) permitted | ||
437 | * | 265 | * |
438 | * Returns 0 on success and < 0 on error. | 266 | * Returns 0 on success and < 0 on error. |
439 | */ | 267 | */ |
@@ -452,10 +280,13 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
452 | if (get_user(pid, &header->pid)) | 280 | if (get_user(pid, &header->pid)) |
453 | return -EFAULT; | 281 | return -EFAULT; |
454 | 282 | ||
283 | /* may only affect current now */ | ||
284 | if (pid != 0 && pid != task_pid_vnr(current)) | ||
285 | return -EPERM; | ||
286 | |||
455 | if (copy_from_user(&kdata, data, tocopy | 287 | if (copy_from_user(&kdata, data, tocopy |
456 | * sizeof(struct __user_cap_data_struct))) { | 288 | * sizeof(struct __user_cap_data_struct))) |
457 | return -EFAULT; | 289 | return -EFAULT; |
458 | } | ||
459 | 290 | ||
460 | for (i = 0; i < tocopy; i++) { | 291 | for (i = 0; i < tocopy; i++) { |
461 | effective.cap[i] = kdata[i].effective; | 292 | effective.cap[i] = kdata[i].effective; |
@@ -473,32 +304,20 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
473 | if (ret) | 304 | if (ret) |
474 | return ret; | 305 | return ret; |
475 | 306 | ||
476 | if (pid && (pid != task_pid_vnr(current))) | 307 | /* This lock is required even when filesystem capability support is |
477 | ret = do_sys_capset_other_tasks(pid, &effective, &inheritable, | 308 | * configured - it protects the sys_capget() call from returning |
478 | &permitted); | 309 | * incorrect data in the case that the targeted process is not the |
479 | else { | 310 | * current one. |
480 | /* | 311 | */ |
481 | * This lock is required even when filesystem | 312 | spin_lock(&task_capability_lock); |
482 | * capability support is configured - it protects the | ||
483 | * sys_capget() call from returning incorrect data in | ||
484 | * the case that the targeted process is not the | ||
485 | * current one. | ||
486 | */ | ||
487 | spin_lock(&task_capability_lock); | ||
488 | |||
489 | ret = security_capset_check(current, &effective, &inheritable, | ||
490 | &permitted); | ||
491 | /* | ||
492 | * Having verified that the proposed changes are | ||
493 | * legal, we now put them into effect. | ||
494 | */ | ||
495 | if (!ret) | ||
496 | security_capset_set(current, &effective, &inheritable, | ||
497 | &permitted); | ||
498 | spin_unlock(&task_capability_lock); | ||
499 | } | ||
500 | |||
501 | 313 | ||
314 | ret = security_capset_check(&effective, &inheritable, &permitted); | ||
315 | /* Having verified that the proposed changes are legal, we now put them | ||
316 | * into effect. | ||
317 | */ | ||
318 | if (!ret) | ||
319 | security_capset_set(&effective, &inheritable, &permitted); | ||
320 | spin_unlock(&task_capability_lock); | ||
502 | return ret; | 321 | return ret; |
503 | } | 322 | } |
504 | 323 | ||