diff options
author | David Howells <dhowells@redhat.com> | 2011-08-22 09:09:11 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-08-22 19:57:36 -0400 |
commit | 8bc16deabce7649e480e94b648c88d4e90c34352 (patch) | |
tree | d9e28a921375e7448801b0b89ff43a7e0d2e61ff | |
parent | 012146d0728f85f7a5c7c36fb84bba33e2760507 (diff) |
KEYS: Move the unreferenced key reaper to the keys garbage collector file
Move the unreferenced key reaper function to the keys garbage collector file
as that's a more appropriate place with the dead key link reaper.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/keys/gc.c | 87 | ||||
-rw-r--r-- | security/keys/internal.h | 2 | ||||
-rw-r--r-- | security/keys/key.c | 72 |
3 files changed, 85 insertions, 76 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c index 89df6b5f203c..b23db3fbb32d 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -10,6 +10,8 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/slab.h> | ||
14 | #include <linux/security.h> | ||
13 | #include <keys/keyring-type.h> | 15 | #include <keys/keyring-type.h> |
14 | #include "internal.h" | 16 | #include "internal.h" |
15 | 17 | ||
@@ -19,12 +21,18 @@ | |||
19 | unsigned key_gc_delay = 5 * 60; | 21 | unsigned key_gc_delay = 5 * 60; |
20 | 22 | ||
21 | /* | 23 | /* |
22 | * Reaper | 24 | * Reaper for unused keys. |
25 | */ | ||
26 | static void key_gc_unused_keys(struct work_struct *work); | ||
27 | DECLARE_WORK(key_gc_unused_work, key_gc_unused_keys); | ||
28 | |||
29 | /* | ||
30 | * Reaper for links from keyrings to dead keys. | ||
23 | */ | 31 | */ |
24 | static void key_gc_timer_func(unsigned long); | 32 | static void key_gc_timer_func(unsigned long); |
25 | static void key_garbage_collector(struct work_struct *); | 33 | static void key_gc_dead_links(struct work_struct *); |
26 | static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); | 34 | static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); |
27 | static DECLARE_WORK(key_gc_work, key_garbage_collector); | 35 | static DECLARE_WORK(key_gc_work, key_gc_dead_links); |
28 | static key_serial_t key_gc_cursor; /* the last key the gc considered */ | 36 | static key_serial_t key_gc_cursor; /* the last key the gc considered */ |
29 | static bool key_gc_again; | 37 | static bool key_gc_again; |
30 | static unsigned long key_gc_executing; | 38 | static unsigned long key_gc_executing; |
@@ -108,10 +116,12 @@ do_gc: | |||
108 | } | 116 | } |
109 | 117 | ||
110 | /* | 118 | /* |
111 | * Garbage collector for keys. This involves scanning the keyrings for dead, | 119 | * Garbage collector for links to dead keys. |
112 | * expired and revoked keys that have overstayed their welcome | 120 | * |
121 | * This involves scanning the keyrings for dead, expired and revoked keys that | ||
122 | * have overstayed their welcome | ||
113 | */ | 123 | */ |
114 | static void key_garbage_collector(struct work_struct *work) | 124 | static void key_gc_dead_links(struct work_struct *work) |
115 | { | 125 | { |
116 | struct rb_node *rb; | 126 | struct rb_node *rb; |
117 | key_serial_t cursor; | 127 | key_serial_t cursor; |
@@ -220,3 +230,68 @@ reached_the_end: | |||
220 | } | 230 | } |
221 | kleave(" [end]"); | 231 | kleave(" [end]"); |
222 | } | 232 | } |
233 | |||
234 | /* | ||
235 | * Garbage collector for unused keys. | ||
236 | * | ||
237 | * This is done in process context so that we don't have to disable interrupts | ||
238 | * all over the place. key_put() schedules this rather than trying to do the | ||
239 | * cleanup itself, which means key_put() doesn't have to sleep. | ||
240 | */ | ||
241 | static void key_gc_unused_keys(struct work_struct *work) | ||
242 | { | ||
243 | struct rb_node *_n; | ||
244 | struct key *key; | ||
245 | |||
246 | go_again: | ||
247 | /* look for a dead key in the tree */ | ||
248 | spin_lock(&key_serial_lock); | ||
249 | |||
250 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | ||
251 | key = rb_entry(_n, struct key, serial_node); | ||
252 | |||
253 | if (atomic_read(&key->usage) == 0) | ||
254 | goto found_dead_key; | ||
255 | } | ||
256 | |||
257 | spin_unlock(&key_serial_lock); | ||
258 | return; | ||
259 | |||
260 | found_dead_key: | ||
261 | /* we found a dead key - once we've removed it from the tree, we can | ||
262 | * drop the lock */ | ||
263 | rb_erase(&key->serial_node, &key_serial_tree); | ||
264 | spin_unlock(&key_serial_lock); | ||
265 | |||
266 | key_check(key); | ||
267 | |||
268 | security_key_free(key); | ||
269 | |||
270 | /* deal with the user's key tracking and quota */ | ||
271 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
272 | spin_lock(&key->user->lock); | ||
273 | key->user->qnkeys--; | ||
274 | key->user->qnbytes -= key->quotalen; | ||
275 | spin_unlock(&key->user->lock); | ||
276 | } | ||
277 | |||
278 | atomic_dec(&key->user->nkeys); | ||
279 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | ||
280 | atomic_dec(&key->user->nikeys); | ||
281 | |||
282 | key_user_put(key->user); | ||
283 | |||
284 | /* now throw away the key memory */ | ||
285 | if (key->type->destroy) | ||
286 | key->type->destroy(key); | ||
287 | |||
288 | kfree(key->description); | ||
289 | |||
290 | #ifdef KEY_DEBUGGING | ||
291 | key->magic = KEY_DEBUG_MAGIC_X; | ||
292 | #endif | ||
293 | kmem_cache_free(key_jar, key); | ||
294 | |||
295 | /* there may, of course, be more than one key to destroy */ | ||
296 | goto go_again; | ||
297 | } | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index f375152a2500..a7cd1a682321 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -75,6 +75,7 @@ extern unsigned key_quota_maxbytes; | |||
75 | #define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ | 75 | #define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ |
76 | 76 | ||
77 | 77 | ||
78 | extern struct kmem_cache *key_jar; | ||
78 | extern struct rb_root key_serial_tree; | 79 | extern struct rb_root key_serial_tree; |
79 | extern spinlock_t key_serial_lock; | 80 | extern spinlock_t key_serial_lock; |
80 | extern struct mutex key_construction_mutex; | 81 | extern struct mutex key_construction_mutex; |
@@ -146,6 +147,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, | |||
146 | 147 | ||
147 | extern long join_session_keyring(const char *name); | 148 | extern long join_session_keyring(const char *name); |
148 | 149 | ||
150 | extern struct work_struct key_gc_unused_work; | ||
149 | extern unsigned key_gc_delay; | 151 | extern unsigned key_gc_delay; |
150 | extern void keyring_gc(struct key *keyring, time_t limit); | 152 | extern void keyring_gc(struct key *keyring, time_t limit); |
151 | extern void key_schedule_gc(time_t expiry_at); | 153 | extern void key_schedule_gc(time_t expiry_at); |
diff --git a/security/keys/key.c b/security/keys/key.c index f7f9d93f08d9..991a15f1e85f 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/user_namespace.h> | 21 | #include <linux/user_namespace.h> |
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | 23 | ||
24 | static struct kmem_cache *key_jar; | 24 | struct kmem_cache *key_jar; |
25 | struct rb_root key_serial_tree; /* tree of keys indexed by serial */ | 25 | struct rb_root key_serial_tree; /* tree of keys indexed by serial */ |
26 | DEFINE_SPINLOCK(key_serial_lock); | 26 | DEFINE_SPINLOCK(key_serial_lock); |
27 | 27 | ||
@@ -36,9 +36,6 @@ unsigned int key_quota_maxbytes = 20000; /* general key space quota */ | |||
36 | static LIST_HEAD(key_types_list); | 36 | static LIST_HEAD(key_types_list); |
37 | static DECLARE_RWSEM(key_types_sem); | 37 | static DECLARE_RWSEM(key_types_sem); |
38 | 38 | ||
39 | static void key_cleanup(struct work_struct *work); | ||
40 | static DECLARE_WORK(key_cleanup_task, key_cleanup); | ||
41 | |||
42 | /* We serialise key instantiation and link */ | 39 | /* We serialise key instantiation and link */ |
43 | DEFINE_MUTEX(key_construction_mutex); | 40 | DEFINE_MUTEX(key_construction_mutex); |
44 | 41 | ||
@@ -591,71 +588,6 @@ int key_reject_and_link(struct key *key, | |||
591 | } | 588 | } |
592 | EXPORT_SYMBOL(key_reject_and_link); | 589 | EXPORT_SYMBOL(key_reject_and_link); |
593 | 590 | ||
594 | /* | ||
595 | * Garbage collect keys in process context so that we don't have to disable | ||
596 | * interrupts all over the place. | ||
597 | * | ||
598 | * key_put() schedules this rather than trying to do the cleanup itself, which | ||
599 | * means key_put() doesn't have to sleep. | ||
600 | */ | ||
601 | static void key_cleanup(struct work_struct *work) | ||
602 | { | ||
603 | struct rb_node *_n; | ||
604 | struct key *key; | ||
605 | |||
606 | go_again: | ||
607 | /* look for a dead key in the tree */ | ||
608 | spin_lock(&key_serial_lock); | ||
609 | |||
610 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | ||
611 | key = rb_entry(_n, struct key, serial_node); | ||
612 | |||
613 | if (atomic_read(&key->usage) == 0) | ||
614 | goto found_dead_key; | ||
615 | } | ||
616 | |||
617 | spin_unlock(&key_serial_lock); | ||
618 | return; | ||
619 | |||
620 | found_dead_key: | ||
621 | /* we found a dead key - once we've removed it from the tree, we can | ||
622 | * drop the lock */ | ||
623 | rb_erase(&key->serial_node, &key_serial_tree); | ||
624 | spin_unlock(&key_serial_lock); | ||
625 | |||
626 | key_check(key); | ||
627 | |||
628 | security_key_free(key); | ||
629 | |||
630 | /* deal with the user's key tracking and quota */ | ||
631 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
632 | spin_lock(&key->user->lock); | ||
633 | key->user->qnkeys--; | ||
634 | key->user->qnbytes -= key->quotalen; | ||
635 | spin_unlock(&key->user->lock); | ||
636 | } | ||
637 | |||
638 | atomic_dec(&key->user->nkeys); | ||
639 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | ||
640 | atomic_dec(&key->user->nikeys); | ||
641 | |||
642 | key_user_put(key->user); | ||
643 | |||
644 | /* now throw away the key memory */ | ||
645 | if (key->type->destroy) | ||
646 | key->type->destroy(key); | ||
647 | |||
648 | kfree(key->description); | ||
649 | |||
650 | #ifdef KEY_DEBUGGING | ||
651 | key->magic = KEY_DEBUG_MAGIC_X; | ||
652 | #endif | ||
653 | kmem_cache_free(key_jar, key); | ||
654 | |||
655 | /* there may, of course, be more than one key to destroy */ | ||
656 | goto go_again; | ||
657 | } | ||
658 | |||
659 | /** | 591 | /** |
660 | * key_put - Discard a reference to a key. | 592 | * key_put - Discard a reference to a key. |
661 | * @key: The key to discard a reference from. | 593 | * @key: The key to discard a reference from. |
@@ -670,7 +602,7 @@ void key_put(struct key *key) | |||
670 | key_check(key); | 602 | key_check(key); |
671 | 603 | ||
672 | if (atomic_dec_and_test(&key->usage)) | 604 | if (atomic_dec_and_test(&key->usage)) |
673 | schedule_work(&key_cleanup_task); | 605 | schedule_work(&key_gc_unused_work); |
674 | } | 606 | } |
675 | } | 607 | } |
676 | EXPORT_SYMBOL(key_put); | 608 | EXPORT_SYMBOL(key_put); |