diff options
author | David Howells <dhowells@redhat.com> | 2005-06-24 01:00:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:05:18 -0400 |
commit | 8589b4e00e352f983259140f25a262d973be6bc5 (patch) | |
tree | d53c9b43ee0aaa2d7518a023c4b6373422117506 | |
parent | 7888e7ff4ee579442128d7d12a9c9dbf2cf7de6a (diff) |
[PATCH] Keys: Use RCU to manage session keyring pointer
The attached patch uses RCU to manage the session keyring pointer in struct
signal_struct. This means that searching need not disable interrupts and get
a the sighand spinlock to access this pointer. Furthermore, by judicious use
of rcu_read_(un)lock(), this patch also avoids the need to take and put
refcounts on the session keyring itself, thus saving on even more atomic ops.
Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | security/keys/process_keys.c | 42 | ||||
-rw-r--r-- | security/keys/request_key.c | 7 |
2 files changed, 24 insertions, 25 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 059c350cac46..972e30172687 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* process_keys.c: management of a process's keyrings | 1 | /* process_keys.c: management of a process's keyrings |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 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 |
@@ -181,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk) | |||
181 | goto error; | 181 | goto error; |
182 | } | 182 | } |
183 | 183 | ||
184 | /* attach or swap keyrings */ | 184 | /* attach keyring */ |
185 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 185 | spin_lock_irqsave(&tsk->sighand->siglock, flags); |
186 | if (!tsk->signal->process_keyring) { | 186 | if (!tsk->signal->process_keyring) { |
187 | tsk->signal->process_keyring = keyring; | 187 | tsk->signal->process_keyring = keyring; |
@@ -227,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk, | |||
227 | 227 | ||
228 | /* install the keyring */ | 228 | /* install the keyring */ |
229 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 229 | spin_lock_irqsave(&tsk->sighand->siglock, flags); |
230 | old = tsk->signal->session_keyring; | 230 | old = rcu_dereference(tsk->signal->session_keyring); |
231 | tsk->signal->session_keyring = keyring; | 231 | rcu_assign_pointer(tsk->signal->session_keyring, keyring); |
232 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 232 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); |
233 | 233 | ||
234 | ret = 0; | 234 | ret = 0; |
235 | 235 | ||
236 | /* we're using RCU on the pointer */ | ||
237 | synchronize_kernel(); | ||
236 | key_put(old); | 238 | key_put(old); |
237 | error: | 239 | error: |
238 | return ret; | 240 | return ret; |
@@ -245,8 +247,6 @@ static int install_session_keyring(struct task_struct *tsk, | |||
245 | */ | 247 | */ |
246 | int copy_thread_group_keys(struct task_struct *tsk) | 248 | int copy_thread_group_keys(struct task_struct *tsk) |
247 | { | 249 | { |
248 | unsigned long flags; | ||
249 | |||
250 | key_check(current->thread_group->session_keyring); | 250 | key_check(current->thread_group->session_keyring); |
251 | key_check(current->thread_group->process_keyring); | 251 | key_check(current->thread_group->process_keyring); |
252 | 252 | ||
@@ -254,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk) | |||
254 | tsk->signal->process_keyring = NULL; | 254 | tsk->signal->process_keyring = NULL; |
255 | 255 | ||
256 | /* same session keyring */ | 256 | /* same session keyring */ |
257 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 257 | rcu_read_lock(); |
258 | tsk->signal->session_keyring = | 258 | tsk->signal->session_keyring = |
259 | key_get(current->signal->session_keyring); | 259 | key_get(rcu_dereference(current->signal->session_keyring)); |
260 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 260 | rcu_read_unlock(); |
261 | 261 | ||
262 | return 0; | 262 | return 0; |
263 | 263 | ||
@@ -381,8 +381,7 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
381 | key_match_func_t match) | 381 | key_match_func_t match) |
382 | { | 382 | { |
383 | struct task_struct *tsk = current; | 383 | struct task_struct *tsk = current; |
384 | unsigned long flags; | 384 | struct key *key, *ret, *err; |
385 | struct key *key, *ret, *err, *tmp; | ||
386 | 385 | ||
387 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 386 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
388 | * searchable, but we failed to find a key or we found a negative key; | 387 | * searchable, but we failed to find a key or we found a negative key; |
@@ -436,17 +435,18 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
436 | } | 435 | } |
437 | 436 | ||
438 | /* search the session keyring last */ | 437 | /* search the session keyring last */ |
439 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 438 | if (tsk->signal->session_keyring) { |
440 | 439 | rcu_read_lock(); | |
441 | tmp = tsk->signal->session_keyring; | 440 | key = keyring_search_aux( |
442 | if (!tmp) | 441 | rcu_dereference(tsk->signal->session_keyring), |
443 | tmp = tsk->user->session_keyring; | 442 | type, description, match); |
444 | atomic_inc(&tmp->usage); | 443 | rcu_read_unlock(); |
445 | 444 | } | |
446 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 445 | else { |
446 | key = keyring_search_aux(tsk->user->session_keyring, | ||
447 | type, description, match); | ||
448 | } | ||
447 | 449 | ||
448 | key = keyring_search_aux(tmp, type, description, match); | ||
449 | key_put(tmp); | ||
450 | if (!IS_ERR(key)) | 450 | if (!IS_ERR(key)) |
451 | goto found; | 451 | goto found; |
452 | 452 | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 1919540f047d..54aa7b70e63b 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -175,13 +175,12 @@ static struct key *__request_key_construction(struct key_type *type, | |||
175 | key->expiry = now.tv_sec + key_negative_timeout; | 175 | key->expiry = now.tv_sec + key_negative_timeout; |
176 | 176 | ||
177 | if (current->signal->session_keyring) { | 177 | if (current->signal->session_keyring) { |
178 | unsigned long flags; | ||
179 | struct key *keyring; | 178 | struct key *keyring; |
180 | 179 | ||
181 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 180 | rcu_read_lock(); |
182 | keyring = current->signal->session_keyring; | 181 | keyring = rcu_dereference(current->signal->session_keyring); |
183 | atomic_inc(&keyring->usage); | 182 | atomic_inc(&keyring->usage); |
184 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 183 | rcu_read_unlock(); |
185 | 184 | ||
186 | key_link(keyring, key); | 185 | key_link(keyring, key); |
187 | key_put(keyring); | 186 | key_put(keyring); |