diff options
author | Michael LeMay <mdlemay@epoch.ncsc.mil> | 2006-06-26 03:24:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:18 -0400 |
commit | e51f6d343789a4f0a2a7587ad7ec7746969d5c1c (patch) | |
tree | 39ca4e05c0dda995f3eaaea1aaa2c8689003f1d0 /security/keys/key.c | |
parent | 5801649d8b83e7cb9b15839761bdee594653c294 (diff) |
[PATCH] keys: allocate key serial numbers randomly
Cause key_alloc_serial() to generate key serial numbers randomly rather than
in linear sequence.
Using an linear sequence permits a covert communication channel to be
established, in which one process can communicate with another by creating or
not creating new keys within a certain timeframe. The second process can
probe for the expected next key serial number and judge its existence by the
error returned.
This is a problem as the serial number namespace is globally shared between
all tasks, regardless of their context.
For more information on this topic, this old TCSEC guide is recommended:
http://www.radium.ncsc.mil/tpep/library/rainbow/NCSC-TG-030.html
Signed-off-by: Michael LeMay <mdlemay@epoch.ncsc.mil>
Signed-off-by: James Morris <jmorris@namei.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index 3601fddca9f2..43295ca37b5d 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -15,11 +15,11 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/security.h> | 16 | #include <linux/security.h> |
17 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
18 | #include <linux/random.h> | ||
18 | #include <linux/err.h> | 19 | #include <linux/err.h> |
19 | #include "internal.h" | 20 | #include "internal.h" |
20 | 21 | ||
21 | static kmem_cache_t *key_jar; | 22 | static kmem_cache_t *key_jar; |
22 | static key_serial_t key_serial_next = 3; | ||
23 | struct rb_root key_serial_tree; /* tree of keys indexed by serial */ | 23 | struct rb_root key_serial_tree; /* tree of keys indexed by serial */ |
24 | DEFINE_SPINLOCK(key_serial_lock); | 24 | DEFINE_SPINLOCK(key_serial_lock); |
25 | 25 | ||
@@ -169,22 +169,23 @@ static void __init __key_insert_serial(struct key *key) | |||
169 | /*****************************************************************************/ | 169 | /*****************************************************************************/ |
170 | /* | 170 | /* |
171 | * assign a key the next unique serial number | 171 | * assign a key the next unique serial number |
172 | * - we work through all the serial numbers between 2 and 2^31-1 in turn and | 172 | * - these are assigned randomly to avoid security issues through covert |
173 | * then wrap | 173 | * channel problems |
174 | */ | 174 | */ |
175 | static inline void key_alloc_serial(struct key *key) | 175 | static inline void key_alloc_serial(struct key *key) |
176 | { | 176 | { |
177 | struct rb_node *parent, **p; | 177 | struct rb_node *parent, **p; |
178 | struct key *xkey; | 178 | struct key *xkey; |
179 | 179 | ||
180 | spin_lock(&key_serial_lock); | 180 | /* propose a random serial number and look for a hole for it in the |
181 | |||
182 | /* propose a likely serial number and look for a hole for it in the | ||
183 | * serial number tree */ | 181 | * serial number tree */ |
184 | key->serial = key_serial_next; | 182 | do { |
185 | if (key->serial < 3) | 183 | get_random_bytes(&key->serial, sizeof(key->serial)); |
186 | key->serial = 3; | 184 | |
187 | key_serial_next = key->serial + 1; | 185 | key->serial >>= 1; /* negative numbers are not permitted */ |
186 | } while (key->serial < 3); | ||
187 | |||
188 | spin_lock(&key_serial_lock); | ||
188 | 189 | ||
189 | parent = NULL; | 190 | parent = NULL; |
190 | p = &key_serial_tree.rb_node; | 191 | p = &key_serial_tree.rb_node; |
@@ -204,12 +205,11 @@ static inline void key_alloc_serial(struct key *key) | |||
204 | 205 | ||
205 | /* we found a key with the proposed serial number - walk the tree from | 206 | /* we found a key with the proposed serial number - walk the tree from |
206 | * that point looking for the next unused serial number */ | 207 | * that point looking for the next unused serial number */ |
207 | serial_exists: | 208 | serial_exists: |
208 | for (;;) { | 209 | for (;;) { |
209 | key->serial = key_serial_next; | 210 | key->serial++; |
210 | if (key->serial < 2) | 211 | if (key->serial < 2) |
211 | key->serial = 2; | 212 | key->serial = 2; |
212 | key_serial_next = key->serial + 1; | ||
213 | 213 | ||
214 | if (!rb_parent(parent)) | 214 | if (!rb_parent(parent)) |
215 | p = &key_serial_tree.rb_node; | 215 | p = &key_serial_tree.rb_node; |
@@ -228,7 +228,7 @@ static inline void key_alloc_serial(struct key *key) | |||
228 | } | 228 | } |
229 | 229 | ||
230 | /* we've found a suitable hole - arrange for this key to occupy it */ | 230 | /* we've found a suitable hole - arrange for this key to occupy it */ |
231 | insert_here: | 231 | insert_here: |
232 | rb_link_node(&key->serial_node, parent, p); | 232 | rb_link_node(&key->serial_node, parent, p); |
233 | rb_insert_color(&key->serial_node, &key_serial_tree); | 233 | rb_insert_color(&key->serial_node, &key_serial_tree); |
234 | 234 | ||