Commit 5d135440faf7db8d566de0c6fab36b16cf9cfc3b

Authored by David Howells
Committed by James Morris
1 parent f041ae2f99

KEYS: Add garbage collection for dead, revoked and expired keys. [try #6]

Add garbage collection for dead, revoked and expired keys.  This involved
erasing all links to such keys from keyrings that point to them.  At that
point, the key will be deleted in the normal manner.

Keyrings from which garbage collection occurs are shrunk and their quota
consumption reduced as appropriate.

Dead keys (for which the key type has been removed) will be garbage collected
immediately.

Revoked and expired keys will hang around for a number of seconds, as set in
/proc/sys/kernel/keys/gc_delay before being automatically removed.  The default
is 5 minutes.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>

Showing 9 changed files with 344 additions and 6 deletions Side-by-side Diff

Documentation/keys.txt
... ... @@ -26,7 +26,7 @@
26 26 - Notes on accessing payload contents
27 27 - Defining a key type
28 28 - Request-key callback service
29   - - Key access filesystem
  29 + - Garbage collection
30 30  
31 31  
32 32 ============
33 33  
... ... @@ -113,7 +113,10 @@
113 113  
114 114 (*) Dead. The key's type was unregistered, and so the key is now useless.
115 115  
  116 +Keys in the last three states are subject to garbage collection. See the
  117 +section on "Garbage collection".
116 118  
  119 +
117 120 ====================
118 121 KEY SERVICE OVERVIEW
119 122 ====================
... ... @@ -1231,4 +1234,18 @@
1231 1234  
1232 1235 In this case, the program isn't required to actually attach the key to a ring;
1233 1236 the rings are provided for reference.
  1237 +
  1238 +
  1239 +==================
  1240 +GARBAGE COLLECTION
  1241 +==================
  1242 +
  1243 +Dead keys (for which the type has been removed) will be automatically unlinked
  1244 +from those keyrings that point to them and deleted as soon as possible by a
  1245 +background garbage collector.
  1246 +
  1247 +Similarly, revoked and expired keys will be garbage collected, but only after a
  1248 +certain amount of time has passed. This time is set as a number of seconds in:
  1249 +
  1250 + /proc/sys/kernel/keys/gc_delay
... ... @@ -129,7 +129,10 @@
129 129 struct rw_semaphore sem; /* change vs change sem */
130 130 struct key_user *user; /* owner of this key */
131 131 void *security; /* security data for this key */
132   - time_t expiry; /* time at which key expires (or 0) */
  132 + union {
  133 + time_t expiry; /* time at which key expires (or 0) */
  134 + time_t revoked_at; /* time at which key was revoked */
  135 + };
133 136 uid_t uid;
134 137 gid_t gid;
135 138 key_perm_t perm; /* access permissions */
security/keys/Makefile
... ... @@ -3,6 +3,7 @@
3 3 #
4 4  
5 5 obj-y := \
  6 + gc.o \
6 7 key.o \
7 8 keyring.o \
8 9 keyctl.o \
  1 +/* Key garbage collector
  2 + *
  3 + * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public Licence
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the Licence, or (at your option) any later version.
  10 + */
  11 +
  12 +#include <linux/module.h>
  13 +#include <keys/keyring-type.h>
  14 +#include "internal.h"
  15 +
  16 +/*
  17 + * Delay between key revocation/expiry in seconds
  18 + */
  19 +unsigned key_gc_delay = 5 * 60;
  20 +
  21 +/*
  22 + * Reaper
  23 + */
  24 +static void key_gc_timer_func(unsigned long);
  25 +static void key_garbage_collector(struct work_struct *);
  26 +static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
  27 +static DECLARE_WORK(key_gc_work, key_garbage_collector);
  28 +static key_serial_t key_gc_cursor; /* the last key the gc considered */
  29 +static unsigned long key_gc_executing;
  30 +static time_t key_gc_next_run = LONG_MAX;
  31 +
  32 +/*
  33 + * Schedule a garbage collection run
  34 + * - precision isn't particularly important
  35 + */
  36 +void key_schedule_gc(time_t gc_at)
  37 +{
  38 + unsigned long expires;
  39 + time_t now = current_kernel_time().tv_sec;
  40 +
  41 + kenter("%ld", gc_at - now);
  42 +
  43 + gc_at += key_gc_delay;
  44 +
  45 + if (now >= gc_at) {
  46 + schedule_work(&key_gc_work);
  47 + } else if (gc_at < key_gc_next_run) {
  48 + expires = jiffies + (gc_at - now) * HZ;
  49 + mod_timer(&key_gc_timer, expires);
  50 + }
  51 +}
  52 +
  53 +/*
  54 + * The garbage collector timer kicked off
  55 + */
  56 +static void key_gc_timer_func(unsigned long data)
  57 +{
  58 + kenter("");
  59 + key_gc_next_run = LONG_MAX;
  60 + schedule_work(&key_gc_work);
  61 +}
  62 +
  63 +/*
  64 + * Garbage collect pointers from a keyring
  65 + * - return true if we altered the keyring
  66 + */
  67 +static bool key_gc_keyring(struct key *keyring, time_t limit)
  68 +{
  69 + struct keyring_list *klist;
  70 + struct key *key;
  71 + int loop;
  72 +
  73 + kenter("%x", key_serial(keyring));
  74 +
  75 + if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
  76 + goto dont_gc;
  77 +
  78 + /* scan the keyring looking for dead keys */
  79 + klist = rcu_dereference(keyring->payload.subscriptions);
  80 + if (!klist)
  81 + goto dont_gc;
  82 +
  83 + for (loop = klist->nkeys - 1; loop >= 0; loop--) {
  84 + key = klist->keys[loop];
  85 + if (test_bit(KEY_FLAG_DEAD, &key->flags) ||
  86 + (key->expiry > 0 && key->expiry <= limit))
  87 + goto do_gc;
  88 + }
  89 +
  90 +dont_gc:
  91 + kleave(" = false");
  92 + return false;
  93 +
  94 +do_gc:
  95 + key_gc_cursor = keyring->serial;
  96 + key_get(keyring);
  97 + spin_unlock(&key_serial_lock);
  98 + keyring_gc(keyring, limit);
  99 + key_put(keyring);
  100 + kleave(" = true");
  101 + return true;
  102 +}
  103 +
  104 +/*
  105 + * Garbage collector for keys
  106 + * - this involves scanning the keyrings for dead, expired and revoked keys
  107 + * that have overstayed their welcome
  108 + */
  109 +static void key_garbage_collector(struct work_struct *work)
  110 +{
  111 + struct rb_node *rb;
  112 + key_serial_t cursor;
  113 + struct key *key, *xkey;
  114 + time_t new_timer = LONG_MAX, limit;
  115 +
  116 + kenter("");
  117 +
  118 + if (test_and_set_bit(0, &key_gc_executing)) {
  119 + key_schedule_gc(current_kernel_time().tv_sec);
  120 + return;
  121 + }
  122 +
  123 + limit = current_kernel_time().tv_sec;
  124 + if (limit > key_gc_delay)
  125 + limit -= key_gc_delay;
  126 + else
  127 + limit = key_gc_delay;
  128 +
  129 + spin_lock(&key_serial_lock);
  130 +
  131 + if (RB_EMPTY_ROOT(&key_serial_tree))
  132 + goto reached_the_end;
  133 +
  134 + cursor = key_gc_cursor;
  135 + if (cursor < 0)
  136 + cursor = 0;
  137 +
  138 + /* find the first key above the cursor */
  139 + key = NULL;
  140 + rb = key_serial_tree.rb_node;
  141 + while (rb) {
  142 + xkey = rb_entry(rb, struct key, serial_node);
  143 + if (cursor < xkey->serial) {
  144 + key = xkey;
  145 + rb = rb->rb_left;
  146 + } else if (cursor > xkey->serial) {
  147 + rb = rb->rb_right;
  148 + } else {
  149 + rb = rb_next(rb);
  150 + if (!rb)
  151 + goto reached_the_end;
  152 + key = rb_entry(rb, struct key, serial_node);
  153 + break;
  154 + }
  155 + }
  156 +
  157 + if (!key)
  158 + goto reached_the_end;
  159 +
  160 + /* trawl through the keys looking for keyrings */
  161 + for (;;) {
  162 + if (key->expiry > 0 && key->expiry < new_timer)
  163 + new_timer = key->expiry;
  164 +
  165 + if (key->type == &key_type_keyring &&
  166 + key_gc_keyring(key, limit)) {
  167 + /* the gc ate our lock */
  168 + schedule_work(&key_gc_work);
  169 + goto no_unlock;
  170 + }
  171 +
  172 + rb = rb_next(&key->serial_node);
  173 + if (!rb) {
  174 + key_gc_cursor = 0;
  175 + break;
  176 + }
  177 + key = rb_entry(rb, struct key, serial_node);
  178 + }
  179 +
  180 +out:
  181 + spin_unlock(&key_serial_lock);
  182 +no_unlock:
  183 + clear_bit(0, &key_gc_executing);
  184 + if (new_timer < LONG_MAX)
  185 + key_schedule_gc(new_timer);
  186 +
  187 + kleave("");
  188 + return;
  189 +
  190 +reached_the_end:
  191 + key_gc_cursor = 0;
  192 + goto out;
  193 +}
security/keys/internal.h
... ... @@ -132,6 +132,10 @@
132 132  
133 133 extern long join_session_keyring(const char *name);
134 134  
  135 +extern unsigned key_gc_delay;
  136 +extern void keyring_gc(struct key *keyring, time_t limit);
  137 +extern void key_schedule_gc(time_t expiry_at);
  138 +
135 139 /*
136 140 * check to see whether permission is granted to use a key in the desired way
137 141 */
... ... @@ -500,6 +500,7 @@
500 500 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
501 501 now = current_kernel_time();
502 502 key->expiry = now.tv_sec + timeout;
  503 + key_schedule_gc(key->expiry);
503 504  
504 505 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
505 506 awaken = 1;
... ... @@ -888,6 +889,9 @@
888 889 */
889 890 void key_revoke(struct key *key)
890 891 {
  892 + struct timespec now;
  893 + time_t time;
  894 +
891 895 key_check(key);
892 896  
893 897 /* make sure no one's trying to change or use the key when we mark it
... ... @@ -900,6 +904,14 @@
900 904 key->type->revoke)
901 905 key->type->revoke(key);
902 906  
  907 + /* set the death time to no more than the expiry time */
  908 + now = current_kernel_time();
  909 + time = now.tv_sec;
  910 + if (key->revoked_at == 0 || key->revoked_at > time) {
  911 + key->revoked_at = time;
  912 + key_schedule_gc(key->revoked_at);
  913 + }
  914 +
903 915 up_write(&key->sem);
904 916  
905 917 } /* end key_revoke() */
... ... @@ -983,6 +995,8 @@
983 995  
984 996 spin_unlock(&key_serial_lock);
985 997 up_write(&key_types_sem);
  998 +
  999 + key_schedule_gc(0);
986 1000  
987 1001 } /* end unregister_key_type() */
988 1002  
security/keys/keyctl.c
... ... @@ -1115,6 +1115,7 @@
1115 1115 }
1116 1116  
1117 1117 key->expiry = expiry;
  1118 + key_schedule_gc(key->expiry);
1118 1119  
1119 1120 up_write(&key->sem);
1120 1121 key_put(key);
security/keys/keyring.c
... ... @@ -1000,4 +1000,89 @@
1000 1000 }
1001 1001  
1002 1002 } /* end keyring_revoke() */
  1003 +
  1004 +/*
  1005 + * Determine whether a key is dead
  1006 + */
  1007 +static bool key_is_dead(struct key *key, time_t limit)
  1008 +{
  1009 + return test_bit(KEY_FLAG_DEAD, &key->flags) ||
  1010 + (key->expiry > 0 && key->expiry <= limit);
  1011 +}
  1012 +
  1013 +/*
  1014 + * Collect garbage from the contents of a keyring
  1015 + */
  1016 +void keyring_gc(struct key *keyring, time_t limit)
  1017 +{
  1018 + struct keyring_list *klist, *new;
  1019 + struct key *key;
  1020 + int loop, keep, max;
  1021 +
  1022 + kenter("%x", key_serial(keyring));
  1023 +
  1024 + down_write(&keyring->sem);
  1025 +
  1026 + klist = keyring->payload.subscriptions;
  1027 + if (!klist)
  1028 + goto just_return;
  1029 +
  1030 + /* work out how many subscriptions we're keeping */
  1031 + keep = 0;
  1032 + for (loop = klist->nkeys - 1; loop >= 0; loop--)
  1033 + if (!key_is_dead(klist->keys[loop], limit));
  1034 + keep++;
  1035 +
  1036 + if (keep == klist->nkeys)
  1037 + goto just_return;
  1038 +
  1039 + /* allocate a new keyring payload */
  1040 + max = roundup(keep, 4);
  1041 + new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
  1042 + GFP_KERNEL);
  1043 + if (!new)
  1044 + goto just_return;
  1045 + new->maxkeys = max;
  1046 + new->nkeys = 0;
  1047 + new->delkey = 0;
  1048 +
  1049 + /* install the live keys
  1050 + * - must take care as expired keys may be updated back to life
  1051 + */
  1052 + keep = 0;
  1053 + for (loop = klist->nkeys - 1; loop >= 0; loop--) {
  1054 + key = klist->keys[loop];
  1055 + if (!key_is_dead(key, limit)) {
  1056 + if (keep >= max)
  1057 + goto discard_new;
  1058 + new->keys[keep++] = key_get(key);
  1059 + }
  1060 + }
  1061 + new->nkeys = keep;
  1062 +
  1063 + /* adjust the quota */
  1064 + key_payload_reserve(keyring,
  1065 + sizeof(struct keyring_list) +
  1066 + KEYQUOTA_LINK_BYTES * keep);
  1067 +
  1068 + if (keep == 0) {
  1069 + rcu_assign_pointer(keyring->payload.subscriptions, NULL);
  1070 + kfree(new);
  1071 + } else {
  1072 + rcu_assign_pointer(keyring->payload.subscriptions, new);
  1073 + }
  1074 +
  1075 + up_write(&keyring->sem);
  1076 +
  1077 + call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
  1078 + kleave(" [yes]");
  1079 + return;
  1080 +
  1081 +discard_new:
  1082 + new->nkeys = keep;
  1083 + keyring_clear_rcu_disposal(&new->rcu);
  1084 +just_return:
  1085 + up_write(&keyring->sem);
  1086 + kleave(" [no]");
  1087 +}
security/keys/sysctl.c
... ... @@ -13,6 +13,8 @@
13 13 #include <linux/sysctl.h>
14 14 #include "internal.h"
15 15  
  16 +static const int zero, one = 1, max = INT_MAX;
  17 +
16 18 ctl_table key_sysctls[] = {
17 19 {
18 20 .ctl_name = CTL_UNNUMBERED,
... ... @@ -20,7 +22,9 @@
20 22 .data = &key_quota_maxkeys,
21 23 .maxlen = sizeof(unsigned),
22 24 .mode = 0644,
23   - .proc_handler = &proc_dointvec,
  25 + .proc_handler = &proc_dointvec_minmax,
  26 + .extra1 = (void *) &one,
  27 + .extra2 = (void *) &max,
24 28 },
25 29 {
26 30 .ctl_name = CTL_UNNUMBERED,
... ... @@ -28,7 +32,9 @@
28 32 .data = &key_quota_maxbytes,
29 33 .maxlen = sizeof(unsigned),
30 34 .mode = 0644,
31   - .proc_handler = &proc_dointvec,
  35 + .proc_handler = &proc_dointvec_minmax,
  36 + .extra1 = (void *) &one,
  37 + .extra2 = (void *) &max,
32 38 },
33 39 {
34 40 .ctl_name = CTL_UNNUMBERED,
... ... @@ -36,7 +42,9 @@
36 42 .data = &key_quota_root_maxkeys,
37 43 .maxlen = sizeof(unsigned),
38 44 .mode = 0644,
39   - .proc_handler = &proc_dointvec,
  45 + .proc_handler = &proc_dointvec_minmax,
  46 + .extra1 = (void *) &one,
  47 + .extra2 = (void *) &max,
40 48 },
41 49 {
42 50 .ctl_name = CTL_UNNUMBERED,
... ... @@ -44,7 +52,19 @@
44 52 .data = &key_quota_root_maxbytes,
45 53 .maxlen = sizeof(unsigned),
46 54 .mode = 0644,
47   - .proc_handler = &proc_dointvec,
  55 + .proc_handler = &proc_dointvec_minmax,
  56 + .extra1 = (void *) &one,
  57 + .extra2 = (void *) &max,
  58 + },
  59 + {
  60 + .ctl_name = CTL_UNNUMBERED,
  61 + .procname = "gc_delay",
  62 + .data = &key_gc_delay,
  63 + .maxlen = sizeof(unsigned),
  64 + .mode = 0644,
  65 + .proc_handler = &proc_dointvec_minmax,
  66 + .extra1 = (void *) &zero,
  67 + .extra2 = (void *) &max,
48 68 },
49 69 { .ctl_name = 0 }
50 70 };