aboutsummaryrefslogtreecommitdiffstats
path: root/security
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
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')
-rw-r--r--security/commoncap.c64
-rw-r--r--security/keys/permission.c10
-rw-r--r--security/keys/process_keys.c24
-rw-r--r--security/selinux/selinuxfs.c13
-rw-r--r--security/smack/smack_lsm.c32
5 files changed, 86 insertions, 57 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}
diff --git a/security/keys/permission.c b/security/keys/permission.c
index baf3d5f31e71..13c36164f284 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -22,13 +22,16 @@ int key_task_permission(const key_ref_t key_ref,
22 struct task_struct *context, 22 struct task_struct *context,
23 key_perm_t perm) 23 key_perm_t perm)
24{ 24{
25 struct cred *cred = context->cred; 25 const struct cred *cred;
26 struct key *key; 26 struct key *key;
27 key_perm_t kperm; 27 key_perm_t kperm;
28 int ret; 28 int ret;
29 29
30 key = key_ref_to_ptr(key_ref); 30 key = key_ref_to_ptr(key_ref);
31 31
32 rcu_read_lock();
33 cred = __task_cred(context);
34
32 /* use the second 8-bits of permissions for keys the caller owns */ 35 /* use the second 8-bits of permissions for keys the caller owns */
33 if (key->uid == cred->fsuid) { 36 if (key->uid == cred->fsuid) {
34 kperm = key->perm >> 16; 37 kperm = key->perm >> 16;
@@ -43,10 +46,7 @@ int key_task_permission(const key_ref_t key_ref,
43 goto use_these_perms; 46 goto use_these_perms;
44 } 47 }
45 48
46 spin_lock(&cred->lock);
47 ret = groups_search(cred->group_info, key->gid); 49 ret = groups_search(cred->group_info, key->gid);
48 spin_unlock(&cred->lock);
49
50 if (ret) { 50 if (ret) {
51 kperm = key->perm >> 8; 51 kperm = key->perm >> 8;
52 goto use_these_perms; 52 goto use_these_perms;
@@ -57,6 +57,8 @@ int key_task_permission(const key_ref_t key_ref,
57 kperm = key->perm; 57 kperm = key->perm;
58 58
59use_these_perms: 59use_these_perms:
60 rcu_read_lock();
61
60 /* use the top 8-bits of permissions for keys the caller possesses 62 /* use the top 8-bits of permissions for keys the caller possesses
61 * - possessor permissions are additive with other permissions 63 * - possessor permissions are additive with other permissions
62 */ 64 */
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index ce8ac6073d57..212601ebaa46 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -412,10 +412,13 @@ key_ref_t search_process_keyrings(struct key_type *type,
412 struct task_struct *context) 412 struct task_struct *context)
413{ 413{
414 struct request_key_auth *rka; 414 struct request_key_auth *rka;
415 struct cred *cred;
415 key_ref_t key_ref, ret, err; 416 key_ref_t key_ref, ret, err;
416 417
417 might_sleep(); 418 might_sleep();
418 419
420 cred = get_task_cred(context);
421
419 /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 422 /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
420 * searchable, but we failed to find a key or we found a negative key; 423 * searchable, but we failed to find a key or we found a negative key;
421 * otherwise we want to return a sample error (probably -EACCES) if 424 * otherwise we want to return a sample error (probably -EACCES) if
@@ -428,9 +431,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
428 err = ERR_PTR(-EAGAIN); 431 err = ERR_PTR(-EAGAIN);
429 432
430 /* search the thread keyring first */ 433 /* search the thread keyring first */
431 if (context->cred->thread_keyring) { 434 if (cred->thread_keyring) {
432 key_ref = keyring_search_aux( 435 key_ref = keyring_search_aux(
433 make_key_ref(context->cred->thread_keyring, 1), 436 make_key_ref(cred->thread_keyring, 1),
434 context, type, description, match); 437 context, type, description, match);
435 if (!IS_ERR(key_ref)) 438 if (!IS_ERR(key_ref))
436 goto found; 439 goto found;
@@ -495,9 +498,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
495 } 498 }
496 } 499 }
497 /* or search the user-session keyring */ 500 /* or search the user-session keyring */
498 else if (context->cred->user->session_keyring) { 501 else if (cred->user->session_keyring) {
499 key_ref = keyring_search_aux( 502 key_ref = keyring_search_aux(
500 make_key_ref(context->cred->user->session_keyring, 1), 503 make_key_ref(cred->user->session_keyring, 1),
501 context, type, description, match); 504 context, type, description, match);
502 if (!IS_ERR(key_ref)) 505 if (!IS_ERR(key_ref))
503 goto found; 506 goto found;
@@ -519,20 +522,20 @@ key_ref_t search_process_keyrings(struct key_type *type,
519 * search the keyrings of the process mentioned there 522 * search the keyrings of the process mentioned there
520 * - we don't permit access to request_key auth keys via this method 523 * - we don't permit access to request_key auth keys via this method
521 */ 524 */
522 if (context->cred->request_key_auth && 525 if (cred->request_key_auth &&
523 context == current && 526 context == current &&
524 type != &key_type_request_key_auth 527 type != &key_type_request_key_auth
525 ) { 528 ) {
526 /* defend against the auth key being revoked */ 529 /* defend against the auth key being revoked */
527 down_read(&context->cred->request_key_auth->sem); 530 down_read(&cred->request_key_auth->sem);
528 531
529 if (key_validate(context->cred->request_key_auth) == 0) { 532 if (key_validate(cred->request_key_auth) == 0) {
530 rka = context->cred->request_key_auth->payload.data; 533 rka = cred->request_key_auth->payload.data;
531 534
532 key_ref = search_process_keyrings(type, description, 535 key_ref = search_process_keyrings(type, description,
533 match, rka->context); 536 match, rka->context);
534 537
535 up_read(&context->cred->request_key_auth->sem); 538 up_read(&cred->request_key_auth->sem);
536 539
537 if (!IS_ERR(key_ref)) 540 if (!IS_ERR(key_ref))
538 goto found; 541 goto found;
@@ -549,7 +552,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
549 break; 552 break;
550 } 553 }
551 } else { 554 } else {
552 up_read(&context->cred->request_key_auth->sem); 555 up_read(&cred->request_key_auth->sem);
553 } 556 }
554 } 557 }
555 558
@@ -557,6 +560,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
557 key_ref = ret ? ret : err; 560 key_ref = ret ? ret : err;
558 561
559found: 562found:
563 put_cred(cred);
560 return key_ref; 564 return key_ref;
561 565
562} /* end search_process_keyrings() */ 566} /* end search_process_keyrings() */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 10715d1330b9..c86303638235 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -95,13 +95,18 @@ extern void selnl_notify_setenforce(int val);
95static int task_has_security(struct task_struct *tsk, 95static int task_has_security(struct task_struct *tsk,
96 u32 perms) 96 u32 perms)
97{ 97{
98 struct task_security_struct *tsec; 98 const struct task_security_struct *tsec;
99 99 u32 sid = 0;
100 tsec = tsk->cred->security; 100
101 rcu_read_lock();
102 tsec = __task_cred(tsk)->security;
103 if (tsec)
104 sid = tsec->sid;
105 rcu_read_unlock();
101 if (!tsec) 106 if (!tsec)
102 return -EACCES; 107 return -EACCES;
103 108
104 return avc_has_perm(tsec->sid, SECINITSID_SECURITY, 109 return avc_has_perm(sid, SECINITSID_SECURITY,
105 SECCLASS_SECURITY, perms, NULL); 110 SECCLASS_SECURITY, perms, NULL);
106} 111}
107 112
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e8a4fcb1ad04..11167fd567b9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -30,6 +30,8 @@
30 30
31#include "smack.h" 31#include "smack.h"
32 32
33#define task_security(task) (task_cred_xxx((task), security))
34
33/* 35/*
34 * I hope these are the hokeyist lines of code in the module. Casey. 36 * I hope these are the hokeyist lines of code in the module. Casey.
35 */ 37 */
@@ -1012,7 +1014,7 @@ static void smack_cred_free(struct cred *cred)
1012 */ 1014 */
1013static int smack_task_setpgid(struct task_struct *p, pid_t pgid) 1015static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
1014{ 1016{
1015 return smk_curacc(p->cred->security, MAY_WRITE); 1017 return smk_curacc(task_security(p), MAY_WRITE);
1016} 1018}
1017 1019
1018/** 1020/**
@@ -1023,7 +1025,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
1023 */ 1025 */
1024static int smack_task_getpgid(struct task_struct *p) 1026static int smack_task_getpgid(struct task_struct *p)
1025{ 1027{
1026 return smk_curacc(p->cred->security, MAY_READ); 1028 return smk_curacc(task_security(p), MAY_READ);
1027} 1029}
1028 1030
1029/** 1031/**
@@ -1034,7 +1036,7 @@ static int smack_task_getpgid(struct task_struct *p)
1034 */ 1036 */
1035static int smack_task_getsid(struct task_struct *p) 1037static int smack_task_getsid(struct task_struct *p)
1036{ 1038{
1037 return smk_curacc(p->cred->security, MAY_READ); 1039 return smk_curacc(task_security(p), MAY_READ);
1038} 1040}
1039 1041
1040/** 1042/**
@@ -1046,7 +1048,7 @@ static int smack_task_getsid(struct task_struct *p)
1046 */ 1048 */
1047static void smack_task_getsecid(struct task_struct *p, u32 *secid) 1049static void smack_task_getsecid(struct task_struct *p, u32 *secid)
1048{ 1050{
1049 *secid = smack_to_secid(p->cred->security); 1051 *secid = smack_to_secid(task_security(p));
1050} 1052}
1051 1053
1052/** 1054/**
@@ -1062,7 +1064,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)
1062 1064
1063 rc = cap_task_setnice(p, nice); 1065 rc = cap_task_setnice(p, nice);
1064 if (rc == 0) 1066 if (rc == 0)
1065 rc = smk_curacc(p->cred->security, MAY_WRITE); 1067 rc = smk_curacc(task_security(p), MAY_WRITE);
1066 return rc; 1068 return rc;
1067} 1069}
1068 1070
@@ -1079,7 +1081,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
1079 1081
1080 rc = cap_task_setioprio(p, ioprio); 1082 rc = cap_task_setioprio(p, ioprio);
1081 if (rc == 0) 1083 if (rc == 0)
1082 rc = smk_curacc(p->cred->security, MAY_WRITE); 1084 rc = smk_curacc(task_security(p), MAY_WRITE);
1083 return rc; 1085 return rc;
1084} 1086}
1085 1087
@@ -1091,7 +1093,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
1091 */ 1093 */
1092static int smack_task_getioprio(struct task_struct *p) 1094static int smack_task_getioprio(struct task_struct *p)
1093{ 1095{
1094 return smk_curacc(p->cred->security, MAY_READ); 1096 return smk_curacc(task_security(p), MAY_READ);
1095} 1097}
1096 1098
1097/** 1099/**
@@ -1109,7 +1111,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
1109 1111
1110 rc = cap_task_setscheduler(p, policy, lp); 1112 rc = cap_task_setscheduler(p, policy, lp);
1111 if (rc == 0) 1113 if (rc == 0)
1112 rc = smk_curacc(p->cred->security, MAY_WRITE); 1114 rc = smk_curacc(task_security(p), MAY_WRITE);
1113 return rc; 1115 return rc;
1114} 1116}
1115 1117
@@ -1121,7 +1123,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
1121 */ 1123 */
1122static int smack_task_getscheduler(struct task_struct *p) 1124static int smack_task_getscheduler(struct task_struct *p)
1123{ 1125{
1124 return smk_curacc(p->cred->security, MAY_READ); 1126 return smk_curacc(task_security(p), MAY_READ);
1125} 1127}
1126 1128
1127/** 1129/**
@@ -1132,7 +1134,7 @@ static int smack_task_getscheduler(struct task_struct *p)
1132 */ 1134 */
1133static int smack_task_movememory(struct task_struct *p) 1135static int smack_task_movememory(struct task_struct *p)
1134{ 1136{
1135 return smk_curacc(p->cred->security, MAY_WRITE); 1137 return smk_curacc(task_security(p), MAY_WRITE);
1136} 1138}
1137 1139
1138/** 1140/**
@@ -1155,13 +1157,13 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
1155 * can write the receiver. 1157 * can write the receiver.
1156 */ 1158 */
1157 if (secid == 0) 1159 if (secid == 0)
1158 return smk_curacc(p->cred->security, MAY_WRITE); 1160 return smk_curacc(task_security(p), MAY_WRITE);
1159 /* 1161 /*
1160 * If the secid isn't 0 we're dealing with some USB IO 1162 * If the secid isn't 0 we're dealing with some USB IO
1161 * specific behavior. This is not clean. For one thing 1163 * specific behavior. This is not clean. For one thing
1162 * we can't take privilege into account. 1164 * we can't take privilege into account.
1163 */ 1165 */
1164 return smk_access(smack_from_secid(secid), p->cred->security, MAY_WRITE); 1166 return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE);
1165} 1167}
1166 1168
1167/** 1169/**
@@ -1174,7 +1176,7 @@ static int smack_task_wait(struct task_struct *p)
1174{ 1176{
1175 int rc; 1177 int rc;
1176 1178
1177 rc = smk_access(current->cred->security, p->cred->security, MAY_WRITE); 1179 rc = smk_access(current_security(), task_security(p), MAY_WRITE);
1178 if (rc == 0) 1180 if (rc == 0)
1179 return 0; 1181 return 0;
1180 1182
@@ -1205,7 +1207,7 @@ static int smack_task_wait(struct task_struct *p)
1205static void smack_task_to_inode(struct task_struct *p, struct inode *inode) 1207static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
1206{ 1208{
1207 struct inode_smack *isp = inode->i_security; 1209 struct inode_smack *isp = inode->i_security;
1208 isp->smk_inode = p->cred->security; 1210 isp->smk_inode = task_security(p);
1209} 1211}
1210 1212
1211/* 1213/*
@@ -2010,7 +2012,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
2010 if (strcmp(name, "current") != 0) 2012 if (strcmp(name, "current") != 0)
2011 return -EINVAL; 2013 return -EINVAL;
2012 2014
2013 cp = kstrdup(p->cred->security, GFP_KERNEL); 2015 cp = kstrdup(task_security(p), GFP_KERNEL);
2014 if (cp == NULL) 2016 if (cp == NULL)
2015 return -ENOMEM; 2017 return -ENOMEM;
2016 2018