summaryrefslogtreecommitdiffstats
path: root/security/keys/key.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-07 13:17:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-07 13:17:46 +0000
commit7f3a4257159dea8e7ef66d1a539dc6df708b8ed3 (patch)
treebcc69b5f4609f348fac49e2f59e210b29eaea783 /security/keys/key.c
parentAdding upstream version 6.9.12. (diff)
downloadlinux-7f3a4257159dea8e7ef66d1a539dc6df708b8ed3.tar.xz
linux-7f3a4257159dea8e7ef66d1a539dc6df708b8ed3.zip
Adding upstream version 6.10.3.upstream/6.10.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/keys/key.c')
-rw-r--r--security/keys/key.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/security/keys/key.c b/security/keys/key.c
index 0aa5f01d16..3d7d185019 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -230,6 +230,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
struct key *key;
size_t desclen, quotalen;
int ret;
+ unsigned long irqflags;
key = ERR_PTR(-EINVAL);
if (!desc || !*desc)
@@ -259,7 +260,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
- spin_lock(&user->lock);
+ spin_lock_irqsave(&user->lock, irqflags);
if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
if (user->qnkeys + 1 > maxkeys ||
user->qnbytes + quotalen > maxbytes ||
@@ -269,7 +270,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
user->qnkeys++;
user->qnbytes += quotalen;
- spin_unlock(&user->lock);
+ spin_unlock_irqrestore(&user->lock, irqflags);
}
/* allocate and initialise the key and its description */
@@ -327,10 +328,10 @@ security_error:
kfree(key->description);
kmem_cache_free(key_jar, key);
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
- spin_lock(&user->lock);
+ spin_lock_irqsave(&user->lock, irqflags);
user->qnkeys--;
user->qnbytes -= quotalen;
- spin_unlock(&user->lock);
+ spin_unlock_irqrestore(&user->lock, irqflags);
}
key_user_put(user);
key = ERR_PTR(ret);
@@ -340,10 +341,10 @@ no_memory_3:
kmem_cache_free(key_jar, key);
no_memory_2:
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
- spin_lock(&user->lock);
+ spin_lock_irqsave(&user->lock, irqflags);
user->qnkeys--;
user->qnbytes -= quotalen;
- spin_unlock(&user->lock);
+ spin_unlock_irqrestore(&user->lock, irqflags);
}
key_user_put(user);
no_memory_1:
@@ -351,7 +352,7 @@ no_memory_1:
goto error;
no_quota:
- spin_unlock(&user->lock);
+ spin_unlock_irqrestore(&user->lock, irqflags);
key_user_put(user);
key = ERR_PTR(-EDQUOT);
goto error;
@@ -380,8 +381,9 @@ int key_payload_reserve(struct key *key, size_t datalen)
if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
+ unsigned long flags;
- spin_lock(&key->user->lock);
+ spin_lock_irqsave(&key->user->lock, flags);
if (delta > 0 &&
(key->user->qnbytes + delta > maxbytes ||
@@ -392,7 +394,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
key->user->qnbytes += delta;
key->quotalen += delta;
}
- spin_unlock(&key->user->lock);
+ spin_unlock_irqrestore(&key->user->lock, flags);
}
/* change the recorded data length if that didn't generate an error */
@@ -646,8 +648,18 @@ void key_put(struct key *key)
if (key) {
key_check(key);
- if (refcount_dec_and_test(&key->usage))
+ if (refcount_dec_and_test(&key->usage)) {
+ unsigned long flags;
+
+ /* deal with the user's key tracking and quota */
+ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+ spin_lock_irqsave(&key->user->lock, flags);
+ key->user->qnkeys--;
+ key->user->qnbytes -= key->quotalen;
+ spin_unlock_irqrestore(&key->user->lock, flags);
+ }
schedule_work(&key_gc_work);
+ }
}
}
EXPORT_SYMBOL(key_put);