diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/keys/gc.c | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c index a42b45531aac..27610bf72195 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -168,38 +168,45 @@ do_gc: | |||
168 | } | 168 | } |
169 | 169 | ||
170 | /* | 170 | /* |
171 | * Garbage collect an unreferenced, detached key | 171 | * Garbage collect a list of unreferenced, detached keys |
172 | */ | 172 | */ |
173 | static noinline void key_gc_unused_key(struct key *key) | 173 | static noinline void key_gc_unused_keys(struct list_head *keys) |
174 | { | 174 | { |
175 | key_check(key); | 175 | while (!list_empty(keys)) { |
176 | 176 | struct key *key = | |
177 | security_key_free(key); | 177 | list_entry(keys->next, struct key, graveyard_link); |
178 | 178 | list_del(&key->graveyard_link); | |
179 | /* deal with the user's key tracking and quota */ | 179 | |
180 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 180 | kdebug("- %u", key->serial); |
181 | spin_lock(&key->user->lock); | 181 | key_check(key); |
182 | key->user->qnkeys--; | 182 | |
183 | key->user->qnbytes -= key->quotalen; | 183 | security_key_free(key); |
184 | spin_unlock(&key->user->lock); | 184 | |
185 | } | 185 | /* deal with the user's key tracking and quota */ |
186 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
187 | spin_lock(&key->user->lock); | ||
188 | key->user->qnkeys--; | ||
189 | key->user->qnbytes -= key->quotalen; | ||
190 | spin_unlock(&key->user->lock); | ||
191 | } | ||
186 | 192 | ||
187 | atomic_dec(&key->user->nkeys); | 193 | atomic_dec(&key->user->nkeys); |
188 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 194 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
189 | atomic_dec(&key->user->nikeys); | 195 | atomic_dec(&key->user->nikeys); |
190 | 196 | ||
191 | key_user_put(key->user); | 197 | key_user_put(key->user); |
192 | 198 | ||
193 | /* now throw away the key memory */ | 199 | /* now throw away the key memory */ |
194 | if (key->type->destroy) | 200 | if (key->type->destroy) |
195 | key->type->destroy(key); | 201 | key->type->destroy(key); |
196 | 202 | ||
197 | kfree(key->description); | 203 | kfree(key->description); |
198 | 204 | ||
199 | #ifdef KEY_DEBUGGING | 205 | #ifdef KEY_DEBUGGING |
200 | key->magic = KEY_DEBUG_MAGIC_X; | 206 | key->magic = KEY_DEBUG_MAGIC_X; |
201 | #endif | 207 | #endif |
202 | kmem_cache_free(key_jar, key); | 208 | kmem_cache_free(key_jar, key); |
209 | } | ||
203 | } | 210 | } |
204 | 211 | ||
205 | /* | 212 | /* |
@@ -211,6 +218,7 @@ static noinline void key_gc_unused_key(struct key *key) | |||
211 | */ | 218 | */ |
212 | static void key_garbage_collector(struct work_struct *work) | 219 | static void key_garbage_collector(struct work_struct *work) |
213 | { | 220 | { |
221 | static LIST_HEAD(graveyard); | ||
214 | static u8 gc_state; /* Internal persistent state */ | 222 | static u8 gc_state; /* Internal persistent state */ |
215 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ | 223 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ |
216 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ | 224 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ |
@@ -316,15 +324,22 @@ maybe_resched: | |||
316 | key_schedule_gc(new_timer); | 324 | key_schedule_gc(new_timer); |
317 | } | 325 | } |
318 | 326 | ||
319 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { | 327 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || |
320 | /* Make sure everyone revalidates their keys if we marked a | 328 | !list_empty(&graveyard)) { |
321 | * bunch as being dead and make sure all keyring ex-payloads | 329 | /* Make sure that all pending keyring payload destructions are |
322 | * are destroyed. | 330 | * fulfilled and that people aren't now looking at dead or |
331 | * dying keys that they don't have a reference upon or a link | ||
332 | * to. | ||
323 | */ | 333 | */ |
324 | kdebug("dead sync"); | 334 | kdebug("gc sync"); |
325 | synchronize_rcu(); | 335 | synchronize_rcu(); |
326 | } | 336 | } |
327 | 337 | ||
338 | if (!list_empty(&graveyard)) { | ||
339 | kdebug("gc keys"); | ||
340 | key_gc_unused_keys(&graveyard); | ||
341 | } | ||
342 | |||
328 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | | 343 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | |
329 | KEY_GC_REAPING_DEAD_2))) { | 344 | KEY_GC_REAPING_DEAD_2))) { |
330 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { | 345 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { |
@@ -359,7 +374,7 @@ found_unreferenced_key: | |||
359 | rb_erase(&key->serial_node, &key_serial_tree); | 374 | rb_erase(&key->serial_node, &key_serial_tree); |
360 | spin_unlock(&key_serial_lock); | 375 | spin_unlock(&key_serial_lock); |
361 | 376 | ||
362 | key_gc_unused_key(key); | 377 | list_add_tail(&key->graveyard_link, &graveyard); |
363 | gc_state |= KEY_GC_REAP_AGAIN; | 378 | gc_state |= KEY_GC_REAP_AGAIN; |
364 | goto maybe_resched; | 379 | goto maybe_resched; |
365 | 380 | ||