Skip to content

Commit

Permalink
[PATCH] Keys: Use RCU to manage session keyring pointer
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Howells authored and Linus Torvalds committed Jun 24, 2005
1 parent 7888e7f commit 8589b4e
Showing 2 changed files with 24 additions and 25 deletions.
42 changes: 21 additions & 21 deletions security/keys/process_keys.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* process_keys.c: management of a process's keyrings
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -181,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk)
goto error;
}

/* attach or swap keyrings */
/* attach keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags);
if (!tsk->signal->process_keyring) {
tsk->signal->process_keyring = keyring;
@@ -227,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk,

/* install the keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags);
old = tsk->signal->session_keyring;
tsk->signal->session_keyring = keyring;
old = rcu_dereference(tsk->signal->session_keyring);
rcu_assign_pointer(tsk->signal->session_keyring, keyring);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);

ret = 0;

/* we're using RCU on the pointer */
synchronize_kernel();
key_put(old);
error:
return ret;
@@ -245,19 +247,17 @@ static int install_session_keyring(struct task_struct *tsk,
*/
int copy_thread_group_keys(struct task_struct *tsk)
{
unsigned long flags;

key_check(current->thread_group->session_keyring);
key_check(current->thread_group->process_keyring);

/* no process keyring yet */
tsk->signal->process_keyring = NULL;

/* same session keyring */
spin_lock_irqsave(&current->sighand->siglock, flags);
rcu_read_lock();
tsk->signal->session_keyring =
key_get(current->signal->session_keyring);
spin_unlock_irqrestore(&current->sighand->siglock, flags);
key_get(rcu_dereference(current->signal->session_keyring));
rcu_read_unlock();

return 0;

@@ -381,8 +381,7 @@ struct key *search_process_keyrings_aux(struct key_type *type,
key_match_func_t match)
{
struct task_struct *tsk = current;
unsigned long flags;
struct key *key, *ret, *err, *tmp;
struct key *key, *ret, *err;

/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* 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,
}

/* search the session keyring last */
spin_lock_irqsave(&tsk->sighand->siglock, flags);

tmp = tsk->signal->session_keyring;
if (!tmp)
tmp = tsk->user->session_keyring;
atomic_inc(&tmp->usage);

spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
if (tsk->signal->session_keyring) {
rcu_read_lock();
key = keyring_search_aux(
rcu_dereference(tsk->signal->session_keyring),
type, description, match);
rcu_read_unlock();
}
else {
key = keyring_search_aux(tsk->user->session_keyring,
type, description, match);
}

key = keyring_search_aux(tmp, type, description, match);
key_put(tmp);
if (!IS_ERR(key))
goto found;

7 changes: 3 additions & 4 deletions security/keys/request_key.c
Original file line number Diff line number Diff line change
@@ -175,13 +175,12 @@ static struct key *__request_key_construction(struct key_type *type,
key->expiry = now.tv_sec + key_negative_timeout;

if (current->signal->session_keyring) {
unsigned long flags;
struct key *keyring;

spin_lock_irqsave(&current->sighand->siglock, flags);
keyring = current->signal->session_keyring;
rcu_read_lock();
keyring = rcu_dereference(current->signal->session_keyring);
atomic_inc(&keyring->usage);
spin_unlock_irqrestore(&current->sighand->siglock, flags);
rcu_read_unlock();

key_link(keyring, key);
key_put(keyring);

0 comments on commit 8589b4e

Please sign in to comment.