diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:19 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:19 -0500 |
commit | c69e8d9c01db2adc503464993c358901c9af9de4 (patch) | |
tree | bed94aaa9aeb7a7834d1c880f72b62a11a752c78 /security/commoncap.c | |
parent | 86a264abe542cfececb4df129bc45a0338d8cdb9 (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.c | 64 |
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 | */ |
52 | int cap_capable(struct task_struct *tsk, int cap, int audit) | 52 | int 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 | ||
60 | int cap_settime(struct timespec *ts, struct timezone *tz) | 63 | int cap_settime(struct timespec *ts, struct timezone *tz) |
@@ -66,34 +69,42 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
66 | 69 | ||
67 | int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) | 70 | int 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 | ||
78 | int cap_ptrace_traceme(struct task_struct *parent) | 83 | int 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 | ||
88 | int cap_capget (struct task_struct *target, kernel_cap_t *effective, | 96 | int 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 | ||
434 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 445 | int 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 | */ |
583 | static int cap_safe_nice(struct task_struct *p) | 594 | static 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 | } |