aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-09-24 05:35:18 -0400
committerDavid Howells <dhowells@redhat.com>2013-09-24 05:35:18 -0400
commitb2a4df200d570b2c33a57e1ebfa5896e4bc81b69 (patch)
tree7fa48ae3c5ecff90d6d1f662fd91af5ddf74d56d
parent3cb989501c2688cacbb7dc4b0d353faf838f53a1 (diff)
KEYS: Expand the capacity of a keyring
Expand the capacity of a keyring to be able to hold a lot more keys by using the previously added associative array implementation. Currently the maximum capacity is: (PAGE_SIZE - sizeof(header)) / sizeof(struct key *) which, on a 64-bit system, is a little more 500. However, since this is being used for the NFS uid mapper, we need more than that. The new implementation gives us effectively unlimited capacity. With some alterations, the keyutils testsuite runs successfully to completion after this patch is applied. The alterations are because (a) keyrings that are simply added to no longer appear ordered and (b) some of the errors have changed a bit. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--include/keys/keyring-type.h17
-rw-r--r--include/linux/key.h13
-rw-r--r--lib/assoc_array.c1
-rw-r--r--security/keys/Kconfig1
-rw-r--r--security/keys/gc.c33
-rw-r--r--security/keys/internal.h17
-rw-r--r--security/keys/key.c35
-rw-r--r--security/keys/keyring.c1436
-rw-r--r--security/keys/request_key.c12
9 files changed, 803 insertions, 762 deletions
diff --git a/include/keys/keyring-type.h b/include/keys/keyring-type.h
index cf49159b0e3a..fca5c62340a4 100644
--- a/include/keys/keyring-type.h
+++ b/include/keys/keyring-type.h
@@ -1,6 +1,6 @@
1/* Keyring key type 1/* Keyring key type
2 * 2 *
3 * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2008, 2013 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -13,19 +13,6 @@
13#define _KEYS_KEYRING_TYPE_H 13#define _KEYS_KEYRING_TYPE_H
14 14
15#include <linux/key.h> 15#include <linux/key.h>
16#include <linux/rcupdate.h> 16#include <linux/assoc_array.h>
17
18/*
19 * the keyring payload contains a list of the keys to which the keyring is
20 * subscribed
21 */
22struct keyring_list {
23 struct rcu_head rcu; /* RCU deletion hook */
24 unsigned short maxkeys; /* max keys this list can hold */
25 unsigned short nkeys; /* number of keys currently held */
26 unsigned short delkey; /* key to be unlinked by RCU */
27 struct key __rcu *keys[0];
28};
29
30 17
31#endif /* _KEYS_KEYRING_TYPE_H */ 18#endif /* _KEYS_KEYRING_TYPE_H */
diff --git a/include/linux/key.h b/include/linux/key.h
index ef596c7af585..2417f789d29b 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -22,6 +22,7 @@
22#include <linux/sysctl.h> 22#include <linux/sysctl.h>
23#include <linux/rwsem.h> 23#include <linux/rwsem.h>
24#include <linux/atomic.h> 24#include <linux/atomic.h>
25#include <linux/assoc_array.h>
25 26
26#ifdef __KERNEL__ 27#ifdef __KERNEL__
27#include <linux/uidgid.h> 28#include <linux/uidgid.h>
@@ -196,11 +197,13 @@ struct key {
196 * whatever 197 * whatever
197 */ 198 */
198 union { 199 union {
199 unsigned long value; 200 union {
200 void __rcu *rcudata; 201 unsigned long value;
201 void *data; 202 void __rcu *rcudata;
202 struct keyring_list __rcu *subscriptions; 203 void *data;
203 } payload; 204 } payload;
205 struct assoc_array keys;
206 };
204}; 207};
205 208
206extern struct key *key_alloc(struct key_type *type, 209extern struct key *key_alloc(struct key_type *type,
diff --git a/lib/assoc_array.c b/lib/assoc_array.c
index a0952818f938..17edeaf19180 100644
--- a/lib/assoc_array.c
+++ b/lib/assoc_array.c
@@ -12,6 +12,7 @@
12 */ 12 */
13//#define DEBUG 13//#define DEBUG
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/err.h>
15#include <linux/assoc_array_priv.h> 16#include <linux/assoc_array_priv.h>
16 17
17/* 18/*
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index a90d6d300dbd..15e0dfe8c80f 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -4,6 +4,7 @@
4 4
5config KEYS 5config KEYS
6 bool "Enable access key retention support" 6 bool "Enable access key retention support"
7 select ASSOCIATIVE_ARRAY
7 help 8 help
8 This option provides support for retaining authentication tokens and 9 This option provides support for retaining authentication tokens and
9 access keys in the kernel. 10 access keys in the kernel.
diff --git a/security/keys/gc.c b/security/keys/gc.c
index d67c97bb1025..cce621c33dce 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -130,6 +130,13 @@ void key_gc_keytype(struct key_type *ktype)
130 kleave(""); 130 kleave("");
131} 131}
132 132
133static int key_gc_keyring_func(const void *object, void *iterator_data)
134{
135 const struct key *key = object;
136 time_t *limit = iterator_data;
137 return key_is_dead(key, *limit);
138}
139
133/* 140/*
134 * Garbage collect pointers from a keyring. 141 * Garbage collect pointers from a keyring.
135 * 142 *
@@ -138,10 +145,9 @@ void key_gc_keytype(struct key_type *ktype)
138 */ 145 */
139static void key_gc_keyring(struct key *keyring, time_t limit) 146static void key_gc_keyring(struct key *keyring, time_t limit)
140{ 147{
141 struct keyring_list *klist; 148 int result;
142 int loop;
143 149
144 kenter("%x", key_serial(keyring)); 150 kenter("%x{%s}", keyring->serial, keyring->description ?: "");
145 151
146 if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | 152 if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
147 (1 << KEY_FLAG_REVOKED))) 153 (1 << KEY_FLAG_REVOKED)))
@@ -149,27 +155,17 @@ static void key_gc_keyring(struct key *keyring, time_t limit)
149 155
150 /* scan the keyring looking for dead keys */ 156 /* scan the keyring looking for dead keys */
151 rcu_read_lock(); 157 rcu_read_lock();
152 klist = rcu_dereference(keyring->payload.subscriptions); 158 result = assoc_array_iterate(&keyring->keys,
153 if (!klist) 159 key_gc_keyring_func, &limit);
154 goto unlock_dont_gc;
155
156 loop = klist->nkeys;
157 smp_rmb();
158 for (loop--; loop >= 0; loop--) {
159 struct key *key = rcu_dereference(klist->keys[loop]);
160 if (key_is_dead(key, limit))
161 goto do_gc;
162 }
163
164unlock_dont_gc:
165 rcu_read_unlock(); 160 rcu_read_unlock();
161 if (result == true)
162 goto do_gc;
163
166dont_gc: 164dont_gc:
167 kleave(" [no gc]"); 165 kleave(" [no gc]");
168 return; 166 return;
169 167
170do_gc: 168do_gc:
171 rcu_read_unlock();
172
173 keyring_gc(keyring, limit); 169 keyring_gc(keyring, limit);
174 kleave(" [gc]"); 170 kleave(" [gc]");
175} 171}
@@ -392,7 +388,6 @@ found_unreferenced_key:
392 */ 388 */
393found_keyring: 389found_keyring:
394 spin_unlock(&key_serial_lock); 390 spin_unlock(&key_serial_lock);
395 kdebug("scan keyring %d", key->serial);
396 key_gc_keyring(key, limit); 391 key_gc_keyring(key, limit);
397 goto maybe_resched; 392 goto maybe_resched;
398 393
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 73950bf8f875..581c6f688352 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -90,20 +90,23 @@ extern void key_type_put(struct key_type *ktype);
90 90
91extern int __key_link_begin(struct key *keyring, 91extern int __key_link_begin(struct key *keyring,
92 const struct keyring_index_key *index_key, 92 const struct keyring_index_key *index_key,
93 unsigned long *_prealloc); 93 struct assoc_array_edit **_edit);
94extern int __key_link_check_live_key(struct key *keyring, struct key *key); 94extern int __key_link_check_live_key(struct key *keyring, struct key *key);
95extern void __key_link(struct key *keyring, struct key *key, 95extern void __key_link(struct key *key, struct assoc_array_edit **_edit);
96 unsigned long *_prealloc);
97extern void __key_link_end(struct key *keyring, 96extern void __key_link_end(struct key *keyring,
98 const