]> Pileus Git - ~andy/linux/blobdiff - security/keys/keyring.c
KEYS: Fix keyring quota misaccounting on key replacement and unlink
[~andy/linux] / security / keys / keyring.c
index 8c05ebd7203d3d25577e818ec91d7fb067fafc93..d80311e571c345a16142fb4fbe2255e234d6a6db 100644 (file)
@@ -1063,12 +1063,6 @@ int __key_link_begin(struct key *keyring,
        if (index_key->type == &key_type_keyring)
                down_write(&keyring_serialise_link_sem);
 
-       /* check that we aren't going to overrun the user's quota */
-       ret = key_payload_reserve(keyring,
-                                 keyring->datalen + KEYQUOTA_LINK_BYTES);
-       if (ret < 0)
-               goto error_sem;
-
        /* Create an edit script that will insert/replace the key in the
         * keyring tree.
         */
@@ -1078,17 +1072,25 @@ int __key_link_begin(struct key *keyring,
                                  NULL);
        if (IS_ERR(edit)) {
                ret = PTR_ERR(edit);
-               goto error_quota;
+               goto error_sem;
+       }
+
+       /* If we're not replacing a link in-place then we're going to need some
+        * extra quota.
+        */
+       if (!edit->dead_leaf) {
+               ret = key_payload_reserve(keyring,
+                                         keyring->datalen + KEYQUOTA_LINK_BYTES);
+               if (ret < 0)
+                       goto error_cancel;
        }
 
        *_edit = edit;
        kleave(" = 0");
        return 0;
 
-error_quota:
-       /* undo the quota changes */
-       key_payload_reserve(keyring,
-                           keyring->datalen - KEYQUOTA_LINK_BYTES);
+error_cancel:
+       assoc_array_cancel_edit(edit);
 error_sem:
        if (index_key->type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
@@ -1146,7 +1148,7 @@ void __key_link_end(struct key *keyring,
        if (index_key->type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 
-       if (edit) {
+       if (edit && !edit->dead_leaf) {
                key_payload_reserve(keyring,
                                    keyring->datalen - KEYQUOTA_LINK_BYTES);
                assoc_array_cancel_edit(edit);
@@ -1243,6 +1245,7 @@ int key_unlink(struct key *keyring, struct key *key)
                goto error;
 
        assoc_array_apply_edit(edit);
+       key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES);
        ret = 0;
 
 error: