]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - security/keys/request_key.c
KEYS: call_sbin_request_key() must write lock keyrings before modifying them
[mv-sheeva.git] / security / keys / request_key.c
index 22a31582bfaae26ffe5911acf72dc2c09e8d06ec..d8c1a6a0fb08e7e86a24be12c64ff6ee13f0a266 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];
@@ -93,7 +94,7 @@ static int call_sbin_request_key(struct key_construction *cons,
        }
 
        /* attach the auth key to the session keyring */
-       ret = __key_link(keyring, authkey);
+       ret = key_link(keyring, authkey);
        if (ret < 0)
                goto error_link;
 
@@ -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);
 
@@ -311,7 +314,8 @@ static int construct_alloc_key(struct key_type *type,
 
        set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
 
-       down_write(&dest_keyring->sem);
+       if (dest_keyring)
+               down_write(&dest_keyring->sem);
 
        /* attach the key to the destination keyring under lock, but we do need
         * to do another check just in case someone beat us to it whilst we
@@ -322,10 +326,12 @@ static int construct_alloc_key(struct key_type *type,
        if (!IS_ERR(key_ref))
                goto key_already_present;
 
-       __key_link(dest_keyring, key);
+       if (dest_keyring)
+               __key_link(dest_keyring, key);
 
        mutex_unlock(&key_construction_mutex);
-       up_write(&dest_keyring->sem);
+       if (dest_keyring)
+               up_write(&dest_keyring->sem);
        mutex_unlock(&user->cons_lock);
        *_key = key;
        kleave(" = 0 [%d]", key_serial(key));
@@ -333,8 +339,10 @@ static int construct_alloc_key(struct key_type *type,
 
 key_already_present:
        mutex_unlock(&key_construction_mutex);
-       if (dest_keyring)
+       if (dest_keyring) {
+               __key_link(dest_keyring, key_ref_to_ptr(key_ref));
                up_write(&dest_keyring->sem);
+       }
        mutex_unlock(&user->cons_lock);
        key_put(key);
        *_key = key = key_ref_to_ptr(key_ref);
@@ -425,6 +433,11 @@ struct key *request_key_and_link(struct key_type *type,
 
        if (!IS_ERR(key_ref)) {
                key = key_ref_to_ptr(key_ref);
+               if (dest_keyring) {
+                       construct_get_dest_keyring(&dest_keyring);
+                       key_link(dest_keyring, key);
+                       key_put(dest_keyring);
+               }
        } else if (PTR_ERR(key_ref) != -EAGAIN) {
                key = ERR_CAST(key_ref);
        } else  {