summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author성병찬 <tjdqudcks0424@naver.com>2026-09-30 13:18:01 +0900
committerJarkko Sakkinen <jarkko@kernel.org>2026-10-04 21:09:32 +0300
commitdd3ea3fcba7c75493760cdbccd35f029597e8d5e (patch)
treeeec349d2859f3c3951d36964ae37c4072df7630e
parent25bf14f817168079f731975b8998fc2af380f29e (diff)
KEYS: Fix add_key() race with keyring restriction
__key_create_or_update() snapshots keyring->restrict_link before taking the destination keyring's semaphore. keyring_restrict() installs a restriction while holding that semaphore. This allows a writer to observe no restriction, wait for the keyring owner to install a reject-all restriction and return successfully, and then link a key using the stale NULL snapshot. The writer only needs write permission on the destination keyring. Move the restrict_link read after __key_link_lock() and __key_link_begin(). The read and the subsequent restriction check are then serialized with restriction installation by keyring->sem. The race was reproduced on v7.2.8 in 19 executions where restriction installation returned before the link completed. All 19 linked the key despite the reject-all restriction. With this change, 312 executions reached the same ordering and every add_key() call failed with -EPERM. The issue was found by manual concurrency analysis assisted by AI-based analysis and independently verified with a QEMU reproducer and kernel instrumentation. Fixes: 5ac7eace2d00 ("KEYS: Add a facility to restrict new links into a keyring") Cc: stable@vger.kernel.org Signed-off-by: 성병찬 <tjdqudcks0424@naver.com> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Link: https://lore.kernel.org/r/20260930041802.6114-1-tjdqudcks0424@naver.com Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
-rw-r--r--security/keys/key.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/security/keys/key.c b/security/keys/key.c
index b34a64d81d47..a438c4508595 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -840,9 +840,6 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
key_check(keyring);
- if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
- restrict_link = keyring->restrict_link;
-
key_ref = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring)
goto error_put_type;
@@ -880,6 +877,9 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
goto error_link_end;
}
+ if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
+ restrict_link = keyring->restrict_link;
+
if (restrict_link && restrict_link->check) {
ret = restrict_link->check(keyring, index_key.type,
&prep.payload, restrict_link->key);