aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:19 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:19 -0500
commitc69e8d9c01db2adc503464993c358901c9af9de4 (patch)
treebed94aaa9aeb7a7834d1c880f72b62a11a752c78 /security/commoncap.c
parent86a264abe542cfececb4df129bc45a0338d8cdb9 (diff)
CRED: Use RCU to access another task's creds and to release a task's own creds
Use RCU to access another task's creds and to release a task's own creds. This means that it will be possible for the credentials of a task to be replaced without another task (a) requiring a full lock to read them, and (b) seeing deallocated memory. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 61307f590003..0384bf95db68 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -51,10 +51,13 @@ EXPORT_SYMBOL(cap_netlink_recv);
51 */ 51 */
52int cap_capable(struct task_struct *tsk, int cap, int audit) 52int cap_capable(struct task_struct *tsk, int cap, int audit)
53{ 53{
54 __u32 cap_raised;
55
54 /* Derived from include/linux/sched.h:capable. */ 56 /* Derived from include/linux/sched.h:capable. */
55 if (cap_raised(tsk->cred->cap_effective, cap)) 57 rcu_read_lock();
56 return 0; 58 cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
57 return -EPERM; 59 rcu_read_unlock();
60 return cap_raised ? 0 : -EPERM;
58} 61}
59 62
60int cap_settime(struct timespec *ts, struct timezone *tz) 63int cap_settime(struct timespec *ts, struct timezone *tz)
@@ -66,34 +69,42 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
66 69
67int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) 70int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
68{ 71{
69 /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ 72 int ret = 0;
70 if (cap_issubset(child->cred->cap_permitted, 73
71 current->cred->cap_permitted)) 74 rcu_read_lock();
72 return 0; 75 if (!cap_issubset(child->cred->cap_permitted,
73 if (capable(CAP_SYS_PTRACE)) 76 current->cred->cap_permitted) &&
74 return 0; 77 !capable(CAP_SYS_PTRACE))
75 return -EPERM; 78 ret = -EPERM;
79 rcu_read_unlock();
80 return ret;
76} 81}
77 82
78int cap_ptrace_traceme(struct task_struct *parent) 83int cap_ptrace_traceme(struct task_struct *parent)
79{ 84{
80 if (cap_issubset(current->cred->cap_permitted, 85 int ret = 0;
81 parent->cred->cap_permitted)) 86
82 return 0; 87 rcu_read_lock();
83 if (has_capability(parent, CAP_SYS_PTRACE)) 88 if (!cap_issubset(current->cred->cap_permitted,
84 return 0; 89 parent->cred->cap_permitted) &&
85 return -EPERM; 90 !has_capability(parent, CAP_SYS_PTRACE))
91 ret = -EPERM;
92 rcu_read_unlock();
93 return ret;
86} 94}
87 95
88int cap_capget (struct task_struct *target, kernel_cap_t *effective, 96int cap_capget (struct task_struct *target, kernel_cap_t *effective,
89 kernel_cap_t *inheritable, kernel_cap_t *permitted) 97 kernel_cap_t *inheritable, kernel_cap_t *permitted)
90{ 98{
91 struct cred *cred = target->cred; 99 const struct cred *cred;
92 100
93 /* Derived from kernel/capability.c:sys_capget. */ 101 /* Derived from kernel/capability.c:sys_capget. */
102 rcu_read_lock();
103 cred = __task_cred(target);
94 *effective = cred->cap_effective; 104 *effective = cred->cap_effective;
95 *inheritable = cred->cap_inheritable; 105 *inheritable = cred->cap_inheritable;
96 *permitted = cred->cap_permitted; 106 *permitted = cred->cap_permitted;
107 rcu_read_unlock();
97 return 0; 108 return 0;
98} 109}
99 110
@@ -433,7 +444,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
433 444
434int cap_bprm_secureexec (struct linux_binprm *bprm) 445int cap_bprm_secureexec (struct linux_binprm *bprm)
435{ 446{
436 const struct cred *cred = current->cred; 447 const struct cred *cred = current_cred();
437 448
438 if (cred->uid != 0) { 449 if (cred->uid != 0) {
439 if (bprm->cap_effective) 450 if (bprm->cap_effective)
@@ -511,11 +522,11 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
511 if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && 522 if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
512 (cred->uid != 0 && cred->euid != 0 && cred->suid != 0) && 523 (cred->uid != 0 && cred->euid != 0 && cred->suid != 0) &&
513 !issecure(SECURE_KEEP_CAPS)) { 524 !issecure(SECURE_KEEP_CAPS)) {
514 cap_clear (cred->cap_permitted); 525 cap_clear(cred->cap_permitted);
515 cap_clear (cred->cap_effective); 526 cap_clear(cred->cap_effective);
516 } 527 }
517 if (old_euid == 0 && cred->euid != 0) { 528 if (old_euid == 0 && cred->euid != 0) {
518 cap_clear (cred->cap_effective); 529 cap_clear(cred->cap_effective);
519 } 530 }
520 if (old_euid != 0 && cred->euid == 0) { 531 if (old_euid != 0 && cred->euid == 0) {
521 cred->cap_effective = cred->cap_permitted; 532 cred->cap_effective = cred->cap_permitted;
@@ -582,9 +593,14 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
582 */ 593 */
583static int cap_safe_nice(struct task_struct *p) 594static int cap_safe_nice(struct task_struct *p)
584{ 595{
585 if (!cap_issubset(p->cred->cap_permitted, 596 int is_subset;
586 current->cred->cap_permitted) && 597
587 !capable(CAP_SYS_NICE)) 598 rcu_read_lock();
599 is_subset = cap_issubset(__task_cred(p)->cap_permitted,
600 current_cred()->cap_permitted);
601 rcu_read_unlock();
602
603 if (!is_subset && !capable(CAP_SYS_NICE))
588 return -EPERM; 604 return -EPERM;
589 return 0; 605 return 0;
590} 606}