aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-14 23:07:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-14 23:07:31 -0400
commit18240904960a39e582ced8ba8ececb10b8c22dd3 (patch)
tree90cbad5533c17657969acb97a0371e41923f7f93
parentf86054c24565d09d1997f03192761dabf6b8a9c9 (diff)
parent8a478905adbb2e09a59644e76f7fe7e0ab644204 (diff)
Merge branch 'for-linus3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: SELinux: inline selinux_is_enabled in !CONFIG_SECURITY_SELINUX KEYS: Fix garbage collector KEYS: Unlock tasklist when exiting early from keyctl_session_to_parent CRED: Allow put_cred() to cope with a NULL groups list SELinux: flush the avc before disabling SELinux SELinux: seperate avc_cache flushing Creds: creds->security can be NULL is selinux is disabled
-rw-r--r--include/linux/cred.h13
-rw-r--r--include/linux/selinux.h9
-rw-r--r--kernel/cred.c3
-rw-r--r--security/keys/gc.c78
-rw-r--r--security/keys/key.c4
-rw-r--r--security/keys/keyctl.c3
-rw-r--r--security/keys/keyring.c24
-rw-r--r--security/selinux/avc.c26
-rw-r--r--security/selinux/exports.c6
9 files changed, 118 insertions, 48 deletions
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 24520a539c6f..fb371601a3b4 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -15,6 +15,7 @@
15#include <linux/capability.h> 15#include <linux/capability.h>
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/key.h> 17#include <linux/key.h>
18#include <linux/selinux.h>
18#include <asm/atomic.h> 19#include <asm/atomic.h>
19 20
20struct user_struct; 21struct user_struct;
@@ -182,11 +183,13 @@ static inline bool creds_are_invalid(const struct cred *cred)
182 if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers)) 183 if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers))
183 return true; 184 return true;
184#ifdef CONFIG_SECURITY_SELINUX 185#ifdef CONFIG_SECURITY_SELINUX
185 if ((unsigned long) cred->security < PAGE_SIZE) 186 if (selinux_is_enabled()) {
186 return true; 187 if ((unsigned long) cred->security < PAGE_SIZE)
187 if ((*(u32*)cred->security & 0xffffff00) == 188 return true;
188 (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) 189 if ((*(u32 *)cred->security & 0xffffff00) ==
189 return true; 190 (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
191 return true;
192 }
190#endif 193#endif
191 return false; 194 return false;
192} 195}
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
index 20f965d4b041..82e0f26a1299 100644
--- a/include/linux/selinux.h
+++ b/include/linux/selinux.h
@@ -61,6 +61,11 @@ void selinux_secmark_refcount_inc(void);
61 * existing SECMARK targets has been removed/flushed. 61 * existing SECMARK targets has been removed/flushed.
62 */ 62 */
63void selinux_secmark_refcount_dec(void); 63void selinux_secmark_refcount_dec(void);
64
65/**
66 * selinux_is_enabled - is SELinux enabled?
67 */
68bool selinux_is_enabled(void);
64#else 69#else
65 70
66static inline int selinux_string_to_sid(const char *str, u32 *sid) 71static inline int selinux_string_to_sid(const char *str, u32 *sid)
@@ -84,6 +89,10 @@ static inline void selinux_secmark_refcount_dec(void)
84 return; 89 return;
85} 90}
86 91
92static inline bool selinux_is_enabled(void)
93{
94 return false;
95}
87#endif /* CONFIG_SECURITY_SELINUX */ 96#endif /* CONFIG_SECURITY_SELINUX */
88 97
89#endif /* _LINUX_SELINUX_H */ 98#endif /* _LINUX_SELINUX_H */
diff --git a/kernel/cred.c b/kernel/cred.c
index 006fcab009d5..d7f7a01082eb 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -147,7 +147,8 @@ static void put_cred_rcu(struct rcu_head *rcu)
147 key_put(cred->thread_keyring); 147 key_put(cred->thread_keyring);
148 key_put(cred->request_key_auth); 148 key_put(cred->request_key_auth);
149 release_tgcred(cred); 149 release_tgcred(cred);
150 put_group_info(cred->group_info); 150 if (cred->group_info)
151 put_group_info(cred->group_info);
151 free_uid(cred->user); 152 free_uid(cred->user);
152 kmem_cache_free(cred_jar, cred); 153 kmem_cache_free(cred_jar, cred);
153} 154}
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 1e616aef55fd..485fc6233c38 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -26,8 +26,10 @@ static void key_garbage_collector(struct work_struct *);
26static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); 26static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
27static DECLARE_WORK(key_gc_work, key_garbage_collector); 27static DECLARE_WORK(key_gc_work, key_garbage_collector);
28static key_serial_t key_gc_cursor; /* the last key the gc considered */ 28static key_serial_t key_gc_cursor; /* the last key the gc considered */
29static bool key_gc_again;
29static unsigned long key_gc_executing; 30static unsigned long key_gc_executing;
30static time_t key_gc_next_run = LONG_MAX; 31static time_t key_gc_next_run = LONG_MAX;
32static time_t key_gc_new_timer;
31 33
32/* 34/*
33 * Schedule a garbage collection run 35 * Schedule a garbage collection run
@@ -40,9 +42,7 @@ void key_schedule_gc(time_t gc_at)
40 42
41 kenter("%ld", gc_at - now); 43 kenter("%ld", gc_at - now);
42 44
43 gc_at += key_gc_delay; 45 if (gc_at <= now) {
44
45 if (now >= gc_at) {
46 schedule_work(&key_gc_work); 46 schedule_work(&key_gc_work);
47 } else if (gc_at < key_gc_next_run) { 47 } else if (gc_at < key_gc_next_run) {
48 expires = jiffies + (gc_at - now) * HZ; 48 expires = jiffies + (gc_at - now) * HZ;
@@ -112,16 +112,18 @@ static void key_garbage_collector(struct work_struct *work)
112 struct rb_node *rb; 112 struct rb_node *rb;
113 key_serial_t cursor; 113 key_serial_t cursor;
114 struct key *key, *xkey; 114 struct key *key, *xkey;
115 time_t new_timer = LONG_MAX, limit; 115 time_t new_timer = LONG_MAX, limit, now;
116 116
117 kenter(""); 117 now = current_kernel_time().tv_sec;
118 kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now);
118 119
119 if (test_and_set_bit(0, &key_gc_executing)) { 120 if (test_and_set_bit(0, &key_gc_executing)) {
120 key_schedule_gc(current_kernel_time().tv_sec); 121 key_schedule_gc(current_kernel_time().tv_sec + 1);
122 kleave(" [busy; deferring]");
121 return; 123 return;
122 } 124 }
123 125
124 limit = current_kernel_time().tv_sec; 126 limit = now;
125 if (limit > key_gc_delay) 127 if (limit > key_gc_delay)
126 limit -= key_gc_delay; 128 limit -= key_gc_delay;
127 else 129 else
@@ -129,12 +131,19 @@ static void key_garbage_collector(struct work_struct *work)
129 131
130 spin_lock(&key_serial_lock); 132 spin_lock(&key_serial_lock);
131 133
132 if (RB_EMPTY_ROOT(&key_serial_tree)) 134 if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) {
133 goto reached_the_end; 135 spin_unlock(&key_serial_lock);
136 clear_bit(0, &key_gc_executing);
137 return;
138 }
134 139
135 cursor = key_gc_cursor; 140 cursor = key_gc_cursor;
136 if (cursor < 0) 141 if (cursor < 0)
137 cursor = 0; 142 cursor = 0;
143 if (cursor > 0)
144 new_timer = key_gc_new_timer;
145 else
146 key_gc_again = false;
138 147
139 /* find the first key above the cursor */ 148 /* find the first key above the cursor */
140 key = NULL; 149 key = NULL;
@@ -160,35 +169,50 @@ static void key_garbage_collector(struct work_struct *work)
160 169
161 /* trawl through the keys looking for keyrings */ 170 /* trawl through the keys looking for keyrings */
162 for (;;) { 171 for (;;) {
163 if (key->expiry > 0 && key->expiry < new_timer) 172 if (key->expiry > now && key->expiry < new_timer) {
173 kdebug("will expire %x in %ld",
174 key_serial(key), key->expiry - now);
164 new_timer = key->expiry; 175 new_timer = key->expiry;
176 }
165 177
166 if (key->type == &key_type_keyring && 178 if (key->type == &key_type_keyring &&
167 key_gc_keyring(key, limit)) { 179 key_gc_keyring(key, limit))
168 /* the gc ate our lock */ 180 /* the gc had to release our lock so that the keyring
169 schedule_work(&key_gc_work); 181 * could be modified, so we have to get it again */
170 goto no_unlock; 182 goto gc_released_our_lock;
171 }
172 183
173 rb = rb_next(&key->serial_node); 184 rb = rb_next(&key->serial_node);
174 if (!rb) { 185 if (!rb)
175 key_gc_cursor = 0; 186 goto reached_the_end;
176 break;
177 }
178 key = rb_entry(rb, struct key, serial_node); 187 key = rb_entry(rb, struct key, serial_node);
179 } 188 }
180 189
181out: 190gc_released_our_lock:
182 spin_unlock(&key_serial_lock); 191 kdebug("gc_released_our_lock");
183no_unlock: 192 key_gc_new_timer = new_timer;
193 key_gc_again = true;
184 clear_bit(0, &key_gc_executing); 194 clear_bit(0, &key_gc_executing);
185 if (new_timer < LONG_MAX) 195 schedule_work(&key_gc_work);
186 key_schedule_gc(new_timer); 196 kleave(" [continue]");
187
188 kleave("");
189 return; 197 return;
190 198
199 /* when we reach the end of the run, we set the timer for the next one */
191reached_the_end: 200reached_the_end:
201 kdebug("reached_the_end");
202 spin_unlock(&key_serial_lock);
203 key_gc_new_timer = new_timer;
192 key_gc_cursor = 0; 204 key_gc_cursor = 0;
193 goto out; 205 clear_bit(0, &key_gc_executing);
206
207 if (key_gc_again) {
208 /* there may have been a key that expired whilst we were
209 * scanning, so if we discarded any links we should do another
210 * scan */
211 new_timer = now + 1;
212 key_schedule_gc(new_timer);
213 } else if (new_timer < LONG_MAX) {
214 new_timer += key_gc_delay;
215 key_schedule_gc(new_timer);
216 }
217 kleave(" [end]");
194} 218}
diff --git a/security/keys/key.c b/security/keys/key.c
index 08531ad0f252..e50d264c9ad1 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -500,7 +500,7 @@ int key_negate_and_link(struct key *key,
500 set_bit(KEY_FLAG_INSTANTIATED, &key->flags); 500 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
501 now = current_kernel_time(); 501 now = current_kernel_time();
502 key->expiry = now.tv_sec + timeout; 502 key->expiry = now.tv_sec + timeout;
503 key_schedule_gc(key->expiry); 503 key_schedule_gc(key->expiry + key_gc_delay);
504 504
505 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) 505 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
506 awaken = 1; 506 awaken = 1;
@@ -909,7 +909,7 @@ void key_revoke(struct key *key)
909 time = now.tv_sec; 909 time = now.tv_sec;
910 if (key->revoked_at == 0 || key->revoked_at > time) { 910 if (key->revoked_at == 0 || key->revoked_at > time) {
911 key->revoked_at = time; 911 key->revoked_at = time;
912 key_schedule_gc(key->revoked_at); 912 key_schedule_gc(key->revoked_at + key_gc_delay);
913 } 913 }
914 914
915 up_write(&key->sem); 915 up_write(&key->sem);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 74c968524592..2fb28efc5326 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1115,7 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
1115 } 1115 }
1116 1116
1117 key->expiry = expiry; 1117 key->expiry = expiry;
1118 key_schedule_gc(key->expiry); 1118 key_schedule_gc(key->expiry + key_gc_delay);
1119 1119
1120 up_write(&key->sem); 1120 up_write(&key->sem);
1121 key_put(key); 1121 key_put(key);
@@ -1319,6 +1319,7 @@ long keyctl_session_to_parent(void)
1319already_same: 1319already_same:
1320 ret = 0; 1320 ret = 0;
1321not_permitted: 1321not_permitted:
1322 write_unlock_irq(&tasklist_lock);
1322 put_cred(cred); 1323 put_cred(cred);
1323 return ret; 1324 return ret;
1324 1325
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index ac977f661a79..8ec02746ca99 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1019,18 +1019,18 @@ void keyring_gc(struct key *keyring, time_t limit)
1019 struct key *key; 1019 struct key *key;
1020 int loop, keep, max; 1020 int loop, keep, max;
1021 1021
1022 kenter("%x", key_serial(keyring)); 1022 kenter("{%x,%s}", key_serial(keyring), keyring->description);
1023 1023
1024 down_write(&keyring->sem); 1024 down_write(&keyring->sem);
1025 1025
1026 klist = keyring->payload.subscriptions; 1026 klist = keyring->payload.subscriptions;
1027 if (!klist) 1027 if (!klist)
1028 goto just_return; 1028 goto no_klist;
1029 1029
1030 /* work out how many subscriptions we're keeping */ 1030 /* work out how many subscriptions we're keeping */
1031 keep = 0; 1031 keep = 0;
1032 for (loop = klist->nkeys - 1; loop >= 0; loop--) 1032 for (loop = klist->nkeys - 1; loop >= 0; loop--)
1033 if (!key_is_dead(klist->keys[loop], limit)); 1033 if (!key_is_dead(klist->keys[loop], limit))
1034 keep++; 1034 keep++;
1035 1035
1036 if (keep == klist->nkeys) 1036 if (keep == klist->nkeys)
@@ -1041,7 +1041,7 @@ void keyring_gc(struct key *keyring, time_t limit)
1041 new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), 1041 new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
1042 GFP_KERNEL); 1042 GFP_KERNEL);
1043 if (!new) 1043 if (!new)
1044 goto just_return; 1044 goto nomem;
1045 new->maxkeys = max; 1045 new->maxkeys = max;
1046 new->nkeys = 0; 1046 new->nkeys = 0;
1047 new->delkey = 0; 1047 new->delkey = 0;
@@ -1081,7 +1081,21 @@ void keyring_gc(struct key *keyring, time_t limit)
1081discard_new: 1081discard_new:
1082 new->nkeys = keep; 1082 new->nkeys = keep;
1083 keyring_clear_rcu_disposal(&new->rcu); 1083 keyring_clear_rcu_disposal(&new->rcu);
1084 up_write(&keyring->sem);
1085 kleave(" [discard]");
1086 return;
1087
1084just_return: 1088just_return:
1085 up_write(&keyring->sem); 1089 up_write(&keyring->sem);
1086 kleave(" [no]"); 1090 kleave(" [no dead]");
1091 return;
1092
1093no_klist:
1094 up_write(&keyring->sem);
1095 kleave(" [no_klist]");
1096 return;
1097
1098nomem:
1099 up_write(&keyring->sem);
1100 kleave(" [oom]");
1087} 1101}
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index e3d19014259b..1ed0f076aadc 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -709,18 +709,16 @@ out:
709} 709}
710 710
711/** 711/**
712 * avc_ss_reset - Flush the cache and revalidate migrated permissions. 712 * avc_flush - Flush the cache
713 * @seqno: policy sequence number
714 */ 713 */
715int avc_ss_reset(u32 seqno) 714static void avc_flush(void)
716{ 715{
717 struct avc_callback_node *c;
718 int i, rc = 0, tmprc;
719 unsigned long flag;
720 struct avc_node *node;
721 struct hlist_head *head; 716 struct hlist_head *head;
722 struct hlist_node *next; 717 struct hlist_node *next;
718 struct avc_node *node;
723 spinlock_t *lock; 719 spinlock_t *lock;
720 unsigned long flag;
721 int i;
724 722
725 for (i = 0; i < AVC_CACHE_SLOTS; i++) { 723 for (i = 0; i < AVC_CACHE_SLOTS; i++) {
726 head = &avc_cache.slots[i]; 724 head = &avc_cache.slots[i];
@@ -737,6 +735,18 @@ int avc_ss_reset(u32 seqno)
737 rcu_read_unlock(); 735 rcu_read_unlock();
738 spin_unlock_irqrestore(lock, flag); 736 spin_unlock_irqrestore(lock, flag);
739 } 737 }
738}
739
740/**
741 * avc_ss_reset - Flush the cache and revalidate migrated permissions.
742 * @seqno: policy sequence number
743 */
744int avc_ss_reset(u32 seqno)
745{
746 struct avc_callback_node *c;
747 int rc = 0, tmprc;
748
749 avc_flush();
740 750
741 for (c = avc_callbacks; c; c = c->next) { 751 for (c = avc_callbacks; c; c = c->next) {
742 if (c->events & AVC_CALLBACK_RESET) { 752 if (c->events & AVC_CALLBACK_RESET) {
@@ -858,6 +868,8 @@ u32 avc_policy_seqno(void)
858 868
859void avc_disable(void) 869void avc_disable(void)
860{ 870{
871 avc_flush();
872 synchronize_rcu();
861 if (avc_node_cachep) 873 if (avc_node_cachep)
862 kmem_cache_destroy(avc_node_cachep); 874 kmem_cache_destroy(avc_node_cachep);
863} 875}
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index c73aeaa008e8..c0a454aee1e0 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -63,3 +63,9 @@ void selinux_secmark_refcount_dec(void)
63 atomic_dec(&selinux_secmark_refcount); 63 atomic_dec(&selinux_secmark_refcount);
64} 64}
65EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); 65EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec);
66
67bool selinux_is_enabled(void)
68{
69 return selinux_enabled;
70}
71EXPORT_SYMBOL_GPL(selinux_is_enabled);