diff options
author | David Howells <dhowells@redhat.com> | 2012-05-11 10:56:56 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2012-05-11 10:56:56 +0100 |
commit | fd75815f727f157a05f4c96b5294a4617c0557da (patch) | |
tree | b2e76abf176d37b5d810b0c813b8c0219754b88c /security/keys/gc.c | |
parent | 31d5a79d7f3d436da176a78ebc12d53c06da402e (diff) |
KEYS: Add invalidation support
Add support for invalidating a key - which renders it immediately invisible to
further searches and causes the garbage collector to immediately wake up,
remove it from keyrings and then destroy it when it's no longer referenced.
It's better not to do this with keyctl_revoke() as that marks the key to start
returning -EKEYREVOKED to searches when what is actually desired is to have the
key refetched.
To invalidate a key the caller must be granted SEARCH permission by the key.
This may be too strict. It may be better to also permit invalidation if the
caller has any of READ, WRITE or SETATTR permission.
The primary use for this is to evict keys that are cached in special keyrings,
such as the DNS resolver or an ID mapper.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'security/keys/gc.c')
-rw-r--r-- | security/keys/gc.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c index adddaa258d50..61ab7c82ebb1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -72,6 +72,15 @@ void key_schedule_gc(time_t gc_at) } /* + * Schedule a dead links collection run. + */ +void key_schedule_gc_links(void) +{ + set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); + queue_work(system_nrt_wq, &key_gc_work); +} + +/* * Some key's cleanup time was met after it expired, so we need to get the * reaper to go through a cycle finding expired keys. */ @@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data) { kenter(""); key_gc_next_run = LONG_MAX; - set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); - queue_work(system_nrt_wq, &key_gc_work); + key_schedule_gc_links(); } /* @@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype) static void key_gc_keyring(struct key *keyring, time_t limit) { struct keyring_list *klist; - struct key *key; int loop; kenter("%x", key_serial(keyring)); - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) + if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED))) goto dont_gc; /* scan the keyring looking for dead keys */ @@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit) loop = klist->nkeys; smp_rmb(); for (loop--; loop >= 0; loop--) { - key = rcu_dereference(klist->keys[loop]); - if (test_bit(KEY_FLAG_DEAD, &key->flags) || - (key->expiry > 0 && key->expiry <= limit)) + struct key *key = rcu_dereference(klist->keys[loop]); + if (key_is_dead(key, limit)) goto do_gc; } |