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 /security | |
| 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>
Diffstat (limited to 'security')
| -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); |
