diff options
| author | Karl Mehltretter <kmehltretter@gmail.com> | 2026-08-21 04:53:27 +0200 |
|---|---|---|
| committer | Jarkko Sakkinen <jarkko@kernel.org> | 2026-09-01 13:23:26 +0300 |
| commit | c00a43cde446edd7c4efcea2278fa692ecbfa7a8 (patch) | |
| tree | 7624f3e43189a982fae2d8c07ae0f8df95ac75b9 | |
| parent | 786262be6048deab760f68c8acc2c85607165894 (diff) | |
| download | linux-next-c00a43cde446edd7c4efcea2278fa692ecbfa7a8.tar.gz linux-next-c00a43cde446edd7c4efcea2278fa692ecbfa7a8.zip | |
keys: fix lost wakeup when reaping a dead key type
clear_bit() is atomic with respect to the word it modifies, but it is
an unordered operation: it implies no memory barrier on either side
(Documentation/atomic_bitops.txt).
key_garbage_collector() clears KEY_GC_REAPING_KEYTYPE with clear_bit()
and calls wake_up_bit() after reaping a dead key type. wake_up_bit()
uses a lockless waitqueue check and requires a full barrier after the
clear.
The existing smp_mb() is before clear_bit(), so nothing orders the clear
against that check. The GC can see an empty waitqueue while
unregister_key_type() still sees the bit set. The final wakeup is then
lost, leaving module unload stuck in wait_on_bit().
Use clear_and_wake_up_bit(). Its clear_bit_unlock() has RELEASE
semantics, so the completed GC work stays ordered before the clear, and
its smp_mb__after_atomic() orders the clear before the waitqueue check.
Fixes: 0c061b5707ab ("KEYS: Correctly destroy key payloads when their keytype is removed")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Link: https://lore.kernel.org/r/20260821025327.61488-1-kmehltretter@gmail.com
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
| -rw-r--r-- | security/keys/gc.c | 4 |
1 files changed, 1 insertions, 3 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c index 748e83818a76..eda445f815d4 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -318,9 +318,7 @@ maybe_resched: if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) { kdebug("dead wake"); - smp_mb(); - clear_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); - wake_up_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE); + clear_and_wake_up_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); } if (gc_state & KEY_GC_REAP_AGAIN) |
