summaryrefslogtreecommitdiff
path: root/security/keys/keyctl.c
diff options
context:
space:
mode:
authorLuis Henriques <lhenriques@suse.de>2024-01-30 10:13:44 +0000
committerJarkko Sakkinen <jarkko@kernel.org>2024-05-09 16:28:58 +0300
commit9578e327b2b4935a25d49e3891b8fcca9b6c10c6 (patch)
tree5b61b324bd79925ebcc6cae2139a4b81a084bd0e /security/keys/keyctl.c
parent45db3ab70092637967967bfd8e6144017638563c (diff)
keys: update key quotas in key_put()
Delaying key quotas update when key's refcount reaches 0 in key_put() has been causing some issues in fscrypt testing, specifically in fstest generic/581. This commit fixes this test flakiness by dealing with the quotas immediately, and leaving all the other clean-ups to the key garbage collector. This is done by moving the updates to the qnkeys and qnbytes fields in struct key_user from key_gc_unused_keys() into key_put(). Unfortunately, this also means that we need to switch to the irq-version of the spinlock that protects these fields and use spin_lock_{irqsave,irqrestore} in all the code that touches these fields. Signed-off-by: Luis Henriques <lhenriques@suse.de> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@kernel.org>
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r--security/keys/keyctl.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 10ba439968f7..4bc3e9398ee3 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -954,6 +954,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
long ret;
kuid_t uid;
kgid_t gid;
+ unsigned long flags;
uid = make_kuid(current_user_ns(), user);
gid = make_kgid(current_user_ns(), group);
@@ -1010,7 +1011,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
- spin_lock(&newowner->lock);
+ spin_lock_irqsave(&newowner->lock, flags);
if (newowner->qnkeys + 1 > maxkeys ||
newowner->qnbytes + key->quotalen > maxbytes ||
newowner->qnbytes + key->quotalen <
@@ -1019,12 +1020,12 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
newowner->qnkeys++;
newowner->qnbytes += key->quotalen;
- spin_unlock(&newowner->lock);
+ spin_unlock_irqrestore(&newowner->lock, flags);
- spin_lock(&key->user->lock);
+ spin_lock_irqsave(&key->user->lock, flags);
key->user->qnkeys--;
key->user->qnbytes -= key->quotalen;
- spin_unlock(&key->user->lock);
+ spin_unlock_irqrestore(&key->user->lock, flags);
}
atomic_dec(&key->user->nkeys);
@@ -1056,7 +1057,7 @@ error:
return ret;
quota_overrun:
- spin_unlock(&newowner->lock);
+ spin_unlock_irqrestore(&newowner->lock, flags);
zapowner = newowner;
ret = -EDQUOT;
goto error_put;