]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - security/keys/keyring.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[karo-tx-linux.git] / security / keys / keyring.c
index 9b6f6e09b50ccdb82b55d88b493c41fd9920c66a..69f0cb7bab7e873f8d8997d71db7c42430f72ce6 100644 (file)
@@ -551,6 +551,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
        if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
                /* we set a different error code if we pass a negative key */
                if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
+                       smp_rmb();
                        ctx->result = ERR_PTR(key->type_data.reject_error);
                        kleave(" = %d [neg]", ctx->skipped_ret);
                        goto skipped;
@@ -1062,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.
         */
@@ -1077,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);
@@ -1145,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);
@@ -1242,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:
@@ -1300,7 +1304,7 @@ static void keyring_revoke(struct key *keyring)
        }
 }
 
-static bool gc_iterator(void *object, void *iterator_data)
+static bool keyring_gc_select_iterator(void *object, void *iterator_data)
 {
        struct key *key = keyring_ptr_to_key(object);
        time_t *limit = iterator_data;
@@ -1311,22 +1315,47 @@ static bool gc_iterator(void *object, void *iterator_data)
        return true;
 }
 
+static int keyring_gc_check_iterator(const void *object, void *iterator_data)
+{
+       const struct key *key = keyring_ptr_to_key(object);
+       time_t *limit = iterator_data;
+
+       key_check(key);
+       return key_is_dead(key, *limit);
+}
+
 /*
- * Collect garbage from the contents of a keyring, replacing the old list with
- * a new one with the pointers all shuffled down.
+ * Garbage collect pointers from a keyring.
  *
- * Dead keys are classed as oned that are flagged as being dead or are revoked,
- * expired or negative keys that were revoked or expired before the specified
- * limit.
+ * Not called with any locks held.  The keyring's key struct will not be
+ * deallocated under us as only our caller may deallocate it.
  */
 void keyring_gc(struct key *keyring, time_t limit)
 {
-       kenter("{%x,%s}", key_serial(keyring), keyring->description);
+       int result;
+
+       kenter("%x{%s}", keyring->serial, keyring->description ?: "");
+
+       if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
+                             (1 << KEY_FLAG_REVOKED)))
+               goto dont_gc;
 
+       /* scan the keyring looking for dead keys */
+       rcu_read_lock();
+       result = assoc_array_iterate(&keyring->keys,
+                                    keyring_gc_check_iterator, &limit);
+       rcu_read_unlock();
+       if (result == true)
+               goto do_gc;
+
+dont_gc:
+       kleave(" [no gc]");
+       return;
+
+do_gc:
        down_write(&keyring->sem);
        assoc_array_gc(&keyring->keys, &keyring_assoc_array_ops,
-                      gc_iterator, &limit);
+                      keyring_gc_select_iterator, &limit);
        up_write(&keyring->sem);
-
-       kleave("");
+       kleave(" [gc]");
 }