usb: ohci: Proper handling of ed_rm_list to handle race condition between usb_kill_ur...
[pandora-kernel.git] / security / keys / request_key.c
index 8246532..a5e32b6 100644 (file)
@@ -267,11 +267,12 @@ static int construct_key(struct key *key, const void *callout_info,
  * The keyring selected is returned with an extra reference upon it which the
  * caller must release.
  */
-static void construct_get_dest_keyring(struct key **_dest_keyring)
+static int construct_get_dest_keyring(struct key **_dest_keyring)
 {
        struct request_key_auth *rka;
        const struct cred *cred = current_cred();
        struct key *dest_keyring = *_dest_keyring, *authkey;
+       int ret;
 
        kenter("%p", dest_keyring);
 
@@ -280,6 +281,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                /* the caller supplied one */
                key_get(dest_keyring);
        } else {
+               bool do_perm_check = true;
+
                /* use a default keyring; falling through the cases until we
                 * find one that we actually have */
                switch (cred->jit_keyring) {
@@ -294,8 +297,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                                        dest_keyring =
                                                key_get(rka->dest_keyring);
                                up_read(&authkey->sem);
-                               if (dest_keyring)
+                               if (dest_keyring) {
+                                       do_perm_check = false;
                                        break;
+                               }
                        }
 
                case KEY_REQKEY_DEFL_THREAD_KEYRING:
@@ -330,11 +335,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                default:
                        BUG();
                }
+
+               /*
+                * Require Write permission on the keyring.  This is essential
+                * because the default keyring may be the session keyring, and
+                * joining a keyring only requires Search permission.
+                *
+                * However, this check is skipped for the "requestor keyring" so
+                * that /sbin/request-key can itself use request_key() to add
+                * keys to the original requestor's destination keyring.
+                */
+               if (dest_keyring && do_perm_check) {
+                       ret = key_permission(make_key_ref(dest_keyring, 1),
+                                            KEY_WRITE);
+                       if (ret) {
+                               key_put(dest_keyring);
+                               return ret;
+                       }
+               }
        }
 
        *_dest_keyring = dest_keyring;
        kleave(" [dk %d]", key_serial(dest_keyring));
-       return;
+       return 0;
 }
 
 /*
@@ -449,11 +472,15 @@ static struct key *construct_key_and_link(struct key_type *type,
 
        kenter("");
 
-       user = key_user_lookup(current_fsuid(), current_user_ns());
-       if (!user)
-               return ERR_PTR(-ENOMEM);
+       ret = construct_get_dest_keyring(&dest_keyring);
+       if (ret)
+               goto error;
 
-       construct_get_dest_keyring(&dest_keyring);
+       user = key_user_lookup(current_fsuid(), current_user_ns());
+       if (!user) {
+               ret = -ENOMEM;
+               goto error_put_dest_keyring;
+       }
 
        ret = construct_alloc_key(type, description, dest_keyring, flags, user,
                                  &key);
@@ -469,7 +496,7 @@ static struct key *construct_key_and_link(struct key_type *type,
        } else if (ret == -EINPROGRESS) {
                ret = 0;
        } else {
-               goto couldnt_alloc_key;
+               goto error_put_dest_keyring;
        }
 
        key_put(dest_keyring);
@@ -479,8 +506,9 @@ static struct key *construct_key_and_link(struct key_type *type,
 construction_failed:
        key_negate_and_link(key, key_negative_timeout, NULL, NULL);
        key_put(key);
-couldnt_alloc_key:
+error_put_dest_keyring:
        key_put(dest_keyring);
+error:
        kleave(" = %d", ret);
        return ERR_PTR(ret);
 }