aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-11-14 08:02:31 -0500
committerDavid Howells <dhowells@redhat.com>2013-11-14 09:09:53 -0500
commit62fe318256befbd1b4a6765e71d9c997f768fe79 (patch)
treea24b4672750ceea1850f7b97131256f163554ea7
parent97826c821ec6724fc359d9b7840dc10af914c641 (diff)
KEYS: Fix keyring content gc scanner
Key pointers stored in the keyring are marked in bit 1 to indicate if they point to a keyring. We need to strip off this bit before using the pointer when iterating over the keyring for the purpose of looking for links to garbage collect. This means that expirable keyrings aren't correctly expiring because the checker is seeing their key pointer with 2 added to it. Since the fix for this involves knowing about the internals of the keyring, key_gc_keyring() is moved to keyring.c and merged into keyring_gc(). This can be tested by: echo 2 >/proc/sys/kernel/keys/gc_delay keyctl timeout `keyctl add keyring qwerty "" @s` 2 cat /proc/keys sleep 5; cat /proc/keys which should see a keyring called "qwerty" appear in the session keyring and then disappear after it expires, and: echo 2 >/proc/sys/kernel/keys/gc_delay a=`keyctl get_persistent @s` b=`keyctl add keyring 0 "" $a` keyctl add user a a $b keyctl timeout $b 2 cat /proc/keys sleep 5; cat /proc/keys which should see a keyring called "0" with a key called "a" in it appear in the user's persistent keyring (which will be attached to the session keyring) and then both the "0" keyring and the "a" key should disappear when the "0" keyring expires. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Simo Sorce <simo@redhat.com>
-rw-r--r--security/keys/gc.c42
-rw-r--r--security/keys/keyring.c45
2 files changed, 36 insertions, 51 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c
index cce621c33dce..d3222b6d7d59 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -130,46 +130,6 @@ 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
140/*
141 * Garbage collect pointers from a keyring.
142 *
143 * Not called with any locks held. The keyring's key struct will not be
144 * deallocated under us as only our caller may deallocate it.
145 */
146static void key_gc_keyring(struct key *keyring, time_t limit)
147{
148 int result;
149
150 kenter("%x{%s}", keyring->serial, keyring->description ?: "");
151
152 if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
153 (1 << KEY_FLAG_REVOKED)))
154 goto dont_gc;
155
156 /* scan the keyring looking for dead keys */
157 rcu_read_lock();
158 result = assoc_array_iterate(&keyring->keys,
159 key_gc_keyring_func, &limit);
160 rcu_read_unlock();
161 if (result == true)
162 goto do_gc;
163
164dont_gc:
165 kleave(" [no gc]");
166 return;
167
168do_gc:
169 keyring_gc(keyring, limit);
170 kleave(" [gc]");
171}
172
173/* 133/*
174 * Garbage collect a list of unreferenced, detached keys 134 * Garbage collect a list of unreferenced, detached keys
175 */ 135 */
@@ -388,7 +348,7 @@ found_unreferenced_key:
388 */ 348 */
389found_keyring: 349found_keyring:
390 spin_unlock(&key_serial_lock); 350 spin_unlock(&key_serial_lock);
391 key_gc_keyring(key, limit); 351 keyring_gc(key, limit);
392 goto maybe_resched; 352 goto maybe_resched;
393 353
394 /* We found a dead key that is still referenced. Reset its type and 354 /* We found a dead key that is still referenced. Reset its type and
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index d80311e571c3..69f0cb7bab7e 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1304,7 +1304,7 @@ static void keyring_revoke(struct key *keyring)
1304 } 1304 }
1305} 1305}
1306 1306
1307static bool gc_iterator(void *object, void *iterator_data) 1307static bool keyring_gc_select_iterator(void *object, void *iterator_data)
1308{ 1308{
1309 struct key *key = keyring_ptr_to_key(object); 1309 struct key *key = keyring_ptr_to_key(object);
1310 time_t *limit = iterator_data; 1310 time_t *limit = iterator_data;
@@ -1315,22 +1315,47 @@ static bool gc_iterator(void *object, void *iterator_data)
1315 return true; 1315 return true;
1316} 1316}
1317 1317
1318static int keyring_gc_check_iterator(const void *object, void *iterator_data)
1319{
1320 const struct key *key = keyring_ptr_to_key(object);
1321 time_t *limit = iterator_data;
1322
1323 key_check(key);
1324 return key_is_dead(key, *limit);
1325}
1326
1318/* 1327/*
1319 * Collect garbage from the contents of a keyring, replacing the old list with 1328 * Garbage collect pointers from a keyring.
1320 * a new one with the pointers all shuffled down.
1321 * 1329 *
1322 * Dead keys are classed as oned that are flagged as being dead or are revoked, 1330 * Not called with any locks held. The keyring's key struct will not be
1323 * expired or negative keys that were revoked or expired before the specified 1331 * deallocated under us as only our caller may deallocate it.
1324 * limit.
1325 */ 1332 */
1326void keyring_gc(struct key *keyring, time_t limit) 1333void keyring_gc(struct key *keyring, time_t limit)
1327{ 1334{
1328 kenter("{%x,%s}", key_serial(keyring), keyring->description); 1335 int result;
1336
1337 kenter("%x{%s}", keyring->serial, keyring->description ?: "");
1329 1338
1339 if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
1340 (1 << KEY_FLAG_REVOKED)))
1341 goto dont_gc;
1342
1343 /* scan the keyring looking for dead keys */
1344 rcu_read_lock();
1345 result = assoc_array_iterate(&keyring->keys,
1346 keyring_gc_check_iterator, &limit);
1347 rcu_read_unlock();
1348 if (result == true)
1349 goto do_gc;
1350
1351dont_gc:
1352 kleave(" [no gc]");
1353 return;
1354
1355do_gc:
1330 down_write(&keyring->sem); 1356 down_write(&keyring->sem);
1331 assoc_array_gc(&keyring->keys, &keyring_assoc_array_ops, 1357 assoc_array_gc(&keyring->keys, &keyring_assoc_array_ops,
1332 gc_iterator, &limit); 1358 keyring_gc_select_iterator, &limit);
1333 up_write(&keyring->sem); 1359 up_write(&keyring->sem);
1334 1360 kleave(" [gc]");
1335 kleave("");
1336} 1361}