keys: fix an RCU warning
authorDavid Howells <dhowells@redhat.com>
Fri, 23 Apr 2010 17:18:00 +0000 (13:18 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 24 Apr 2010 18:31:25 +0000 (11:31 -0700)
Fix the following RCU warning:

  ===================================================
  [ INFO: suspicious rcu_dereference_check() usage. ]
  ---------------------------------------------------
  security/keys/request_key.c:116 invoked rcu_dereference_check() without protection!

This was caused by doing:

[root@andromeda ~]# keyctl newring fred @s
539196288
[root@andromeda ~]# keyctl request2 user a a 539196288
request_key: Required key not available

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
security/keys/request_key.c

index 03fe63ed55bda1a1cfacc95138e409e8ef53f0d2..ea97c3120d6624bdae19907e0ba09afecb0bc4dd 100644 (file)
@@ -68,7 +68,8 @@ static int call_sbin_request_key(struct key_construction *cons,
 {
        const struct cred *cred = current_cred();
        key_serial_t prkey, sskey;
-       struct key *key = cons->key, *authkey = cons->authkey, *keyring;
+       struct key *key = cons->key, *authkey = cons->authkey, *keyring,
+               *session;
        char *argv[9], *envp[3], uid_str[12], gid_str[12];
        char key_str[12], keyring_str[3][12];
        char desc[20];
@@ -112,10 +113,12 @@ static int call_sbin_request_key(struct key_construction *cons,
        if (cred->tgcred->process_keyring)
                prkey = cred->tgcred->process_keyring->serial;
 
-       if (cred->tgcred->session_keyring)
-               sskey = rcu_dereference(cred->tgcred->session_keyring)->serial;
-       else
-               sskey = cred->user->session_keyring->serial;
+       rcu_read_lock();
+       session = rcu_dereference(cred->tgcred->session_keyring);
+       if (!session)
+               session = cred->user->session_keyring;
+       sskey = session->serial;
+       rcu_read_unlock();
 
        sprintf(keyring_str[2], "%d", sskey);