diff options
| -rw-r--r-- | Documentation/keys.txt | 19 | ||||
| -rw-r--r-- | include/linux/key.h | 5 | ||||
| -rw-r--r-- | security/keys/Makefile | 1 | ||||
| -rw-r--r-- | security/keys/gc.c | 193 | ||||
| -rw-r--r-- | security/keys/internal.h | 4 | ||||
| -rw-r--r-- | security/keys/key.c | 14 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 1 | ||||
| -rw-r--r-- | security/keys/keyring.c | 85 | ||||
| -rw-r--r-- | security/keys/sysctl.c | 28 |
9 files changed, 344 insertions, 6 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index b56aacc1fff8..203487e9b1d8 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
| @@ -26,7 +26,7 @@ This document has the following sections: | |||
| 26 | - Notes on accessing payload contents | 26 | - Notes on accessing payload contents |
| 27 | - Defining a key type | 27 | - Defining a key type |
| 28 | - Request-key callback service | 28 | - Request-key callback service |
| 29 | - Key access filesystem | 29 | - Garbage collection |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | ============ | 32 | ============ |
| @@ -113,6 +113,9 @@ Each key has a number of attributes: | |||
| 113 | 113 | ||
| 114 | (*) Dead. The key's type was unregistered, and so the key is now useless. | 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". | ||
| 118 | |||
| 116 | 119 | ||
| 117 | ==================== | 120 | ==================== |
| 118 | KEY SERVICE OVERVIEW | 121 | KEY SERVICE OVERVIEW |
| @@ -1231,3 +1234,17 @@ by executing: | |||
| 1231 | 1234 | ||
| 1232 | In this case, the program isn't required to actually attach the key to a ring; | 1235 | In this case, the program isn't required to actually attach the key to a ring; |
| 1233 | the rings are provided for reference. | 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 | ||
diff --git a/include/linux/key.h b/include/linux/key.h index e544f466d69a..33e0165de100 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -129,7 +129,10 @@ struct key { | |||
| 129 | struct rw_semaphore sem; /* change vs change sem */ | 129 | struct rw_semaphore sem; /* change vs change sem */ |
| 130 | struct key_user *user; /* owner of this key */ | 130 | struct key_user *user; /* owner of this key */ |
| 131 | void *security; /* security data for this key */ | 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 | uid_t uid; | 136 | uid_t uid; |
| 134 | gid_t gid; | 137 | gid_t gid; |
| 135 | key_perm_t perm; /* access permissions */ | 138 | key_perm_t perm; /* access permissions */ |
diff --git a/security/keys/Makefile b/security/keys/Makefile index 747a464943af..74d5447d7df7 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := \ | 5 | obj-y := \ |
| 6 | gc.o \ | ||
| 6 | key.o \ | 7 | key.o \ |
| 7 | keyring.o \ | 8 | keyring.o \ |
| 8 | keyctl.o \ | 9 | keyctl.o \ |
diff --git a/security/keys/gc.c b/security/keys/gc.c new file mode 100644 index 000000000000..44adc325e15c --- /dev/null +++ b/security/keys/gc.c | |||
| @@ -0,0 +1,193 @@ | |||
| 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 | |||
