keyring_clear() and key_invalidate() release keyring links via call_rcu(), and key_put() defers final key destruction to key_gc_work. Once keys pin their type, callers that clear an internal cache before module unload need a synchronous barrier so module references can be dropped before delete_module() checks the refcount. Add key_gc_flush() for flushing the remaining key_gc_work passes. Signed-off-by: Jarkko Sakkinen --- include/linux/key.h | 2 ++ security/keys/gc.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/linux/key.h b/include/linux/key.h index 420412aab926..0f408255f740 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -439,6 +439,7 @@ extern int restrict_link_reject(struct key *keyring, struct key *restriction_key); extern int keyring_clear(struct key *keyring); +void key_gc_flush(void); extern key_ref_t keyring_search(key_ref_t keyring, struct key_type *type, @@ -526,6 +527,7 @@ extern void key_init(void); #define key_free_user_ns(ns) do { } while(0) #define key_remove_domain(d) do { } while(0) #define key_lookup(k) NULL +#define key_gc_flush() do { } while (0) #endif /* CONFIG_KEYS */ #endif /* __KERNEL__ */ diff --git a/security/keys/gc.c b/security/keys/gc.c index eda445f815d4..2c3eddc0443a 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -21,6 +21,17 @@ unsigned key_gc_delay = 5 * 60; static void key_garbage_collector(struct work_struct *work); DECLARE_WORK(key_gc_work, key_garbage_collector); +/** + * key_gc_flush - Drain the garbage collector RCU callbacks + */ +void key_gc_flush(void) +{ + do { + rcu_barrier(); + } while (flush_work(&key_gc_work)); +} +EXPORT_SYMBOL_GPL(key_gc_flush); + /* * Reaper for links from keyrings to dead keys. */ -- 2.47.3