[PATCH RFC v3 11/90] keys: add key_user_range_in_use()
From: Josef Bacik
Date: Thu Nov 05 2026 - 10:00:01 EST
The key quota record of a user is looked up by a bare kuid and does not
pin a user namespace. The record, and possibly keys that are charged to
it, can still exist after the cell that used the kuid is gone. If the
block is then lent to another cell, that cell would find them.
Add key_user_range_in_use(), so that the block allocator can ask whether a
quota record exists for any kuid in a range.
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
include/linux/key.h | 2 ++
security/keys/key.c | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/include/linux/key.h b/include/linux/key.h
index 115db6e60254..0bd77fcab4db 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -461,6 +461,7 @@ extern void key_set_timeout(struct key *, unsigned);
extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
enum key_need_perm need_perm);
extern void key_free_user_ns(struct user_namespace *);
+bool key_user_range_in_use(kuid_t first, kuid_t last);
static inline short key_read_state(const struct key *key)
{
@@ -521,6 +522,7 @@ extern void key_init(void);
#define key_fsgid_changed(c) do { } while(0)
#define key_init() do { } while(0)
#define key_free_user_ns(ns) do { } while(0)
+static inline bool key_user_range_in_use(kuid_t first, kuid_t last) { return false; }
#define key_remove_domain(d) do { } while(0)
#define key_lookup(k) NULL
diff --git a/security/keys/key.c b/security/keys/key.c
index 6ebb8691551f..0a6e741805d6 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -113,6 +113,44 @@ struct key_user *key_user_lookup(kuid_t uid)
return user;
}
+#ifdef CONFIG_CELLS
+struct key_user_range {
+ kuid_t first;
+ kuid_t last;
+};
+
+static int key_user_range_cmp(const void *key, const struct rb_node *n)
+{
+ const struct key_user *user = rb_entry(n, struct key_user, node);
+ const struct key_user_range *range = key;
+
+ if (uid_lt(range->last, user->uid))
+ return -1;
+ if (uid_gt(range->first, user->uid))
+ return 1;
+ return 0;
+}
+
+/**
+ * key_user_range_in_use - is there a quota record for any uid of a range?
+ * @first: the first uid of the range
+ * @last: the last
+ *
+ * A quota record, and so possibly a key, is keyed by a bare kuid and pins no
+ * user namespace. The id block allocator asks before it lends a block, and
+ * before it takes one back.
+ *
+ * Return: true if there is one.
+ */
+bool key_user_range_in_use(kuid_t first, kuid_t last)
+{
+ struct key_user_range range = { .first = first, .last = last };
+
+ guard(spinlock)(&key_user_lock);
+ return rb_find(&range, &key_user_tree, key_user_range_cmp);
+}
+#endif
+
/*
* Dispose of a user structure
*/
--
2.55.0