keyring_clear() and key_invalidate() release keyring links via call_rcu(),
and key_put() defers final key destruction to key_gc_work.
Once live keys pin the key type until key_gc_unused_keys(), callers that
clear an internal cache before module unload need a synchronous barrier so
module references are dropped before delete_module() checks the refcount.
Add key_gc_flush() for draining RCU callbacks and flush key_gc_work until
no further garbage collection passes remain queued.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
include/linux/key.h | 2 ++
security/keys/gc.c | 14 ++++++++++++++
2 files changed, 16 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..3cfbf00085b3 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -21,6 +21,20 @@ 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 - Wait for pending key unlinks and garbage collection.
+ *
+ * Drain RCU callbacks from keyring edits and wait for the key garbage
+ * collector work item to finish reaping unreferenced keys.
+ */
+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