summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-27 08:01:30 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-27 08:01:30 -1000
commit62c457528529cdcfa32bc52b331ceca10f3937b6 (patch)
tree996f24181b89b02cbc2afcbe74888590877e9639
parentc60ebc3208b9ce1d8915318347962f7ce1dbd07d (diff)
parent503b65da9a7e5447d91222f62399522f2f62a0fa (diff)
downloadlinux-next-62c457528529cdcfa32bc52b331ceca10f3937b6.tar.gz
linux-next-62c457528529cdcfa32bc52b331ceca10f3937b6.zip
Merge tag 'vfs-7.4-rc1.keyring' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs keyring updates from Christian Brauner: "The kernel has two keyrings that userspace fills with X.509 certificates at boot: .fs-verity for fs-verity built-in signatures and .dm-verity for dm-verity root hash signatures. Neither is linked into any process keyring. Hence, request_key() and KEYCTL_SEARCH can't find them. The only way for userspace to identify them is to read their serial number out of /proc/keys. That is not just a large file often the names can also be reused and appear multiple times which allows forging these keyrings. This adds two fixed special key ids, KEY_SPEC_DM_VERITY_KEYRING and KEY_SPEC_FS_VERITY_KEYRING next to KEY_SPEC_BPF_KEYRING. The latter went in through bpf-next this merge window. lookup_user_key() resolves the fixed key ids to the two keyrings. So userspace can add a dm-verity (fixed keyring id: -10) certificate with keyctl padd asymmetric "" -10 < cert.der and seal the keyring with keyctl restrict_keyring -10 without looking anything up first" * tag 'vfs-7.4-rc1.keyring' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: Documentation: keys: document IDs added since KEY_SPEC_REQKEY_AUTH_KEY keys: add KEY_SPEC_FS_VERITY_KEYRING keys: add KEY_SPEC_DM_VERITY_KEYRING
-rw-r--r--Documentation/security/keys/core.rst13
-rw-r--r--drivers/md/dm-verity-verify-sig.c3
-rw-r--r--fs/verity/signature.c2
-rw-r--r--include/linux/key.h2
-rw-r--r--include/uapi/linux/keyctl.h2
-rw-r--r--security/keys/process_keys.c58
6 files changed, 80 insertions, 0 deletions
diff --git a/Documentation/security/keys/core.rst b/Documentation/security/keys/core.rst
index 326b8a973828..37ed42382f16 100644
--- a/Documentation/security/keys/core.rst
+++ b/Documentation/security/keys/core.rst
@@ -372,6 +372,19 @@ process making the call::
KEY_SPEC_GROUP_KEYRING -6 GID-specific keyring
KEY_SPEC_REQKEY_AUTH_KEY -7 assumed request_key()
authorisation key
+ KEY_SPEC_REQUESTOR_KEYRING -8 request_key() destination
+ keyring
+
+There are also values that refer to a specific kernel keyring rather than to
+anything belonging to the caller. These keyrings are not linked into any
+keyring, so a search cannot reach them and the ID is the only way to name
+one::
+
+ CONSTANT VALUE KEY REFERENCED
+ ============================== ====== ===========================
+ KEY_SPEC_BPF_KEYRING -9 the ".bpf" keyring
+ KEY_SPEC_DM_VERITY_KEYRING -10 the ".dm-verity" keyring
+ KEY_SPEC_FS_VERITY_KEYRING -11 the ".fs-verity" keyring
The main syscalls are:
diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
index aadcf5e4a47c..0c65c7a31da8 100644
--- a/drivers/md/dm-verity-verify-sig.c
+++ b/drivers/md/dm-verity-verify-sig.c
@@ -189,11 +189,14 @@ int __init dm_verity_verify_sig_init(void)
keyring_restrict(make_key_ref(dm_verity_keyring, true), NULL, NULL))
panic("dm-verity can't seal keyring\n");
+ key_register_dm_verity_keyring(dm_verity_keyring);
+
return 0;
}
void dm_verity_verify_sig_exit(void)
{
+ key_register_dm_verity_keyring(NULL);
key_revoke(dm_verity_keyring);
key_put(dm_verity_keyring);
}
diff --git a/fs/verity/signature.c b/fs/verity/signature.c
index 0302a4e506ec..07657e913b22 100644
--- a/fs/verity/signature.c
+++ b/fs/verity/signature.c
@@ -135,4 +135,6 @@ void __init fsverity_init_signature(void)
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(fsverity_keyring))
panic("failed to allocate \".fs-verity\" keyring");
+
+ key_register_fs_verity_keyring(fsverity_keyring);
}
diff --git a/include/linux/key.h b/include/linux/key.h
index dae5ba255ad1..115db6e60254 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -446,6 +446,8 @@ extern int keyring_restrict(key_ref_t keyring, const char *type,
const char *restriction);
extern void key_register_bpf_keyring(struct key *keyring);
+extern void key_register_dm_verity_keyring(struct key *keyring);
+extern void key_register_fs_verity_keyring(struct key *keyring);
extern struct key *key_lookup(key_serial_t id);
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index fa85b9760391..00cc0942203e 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -25,6 +25,8 @@
#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */
#define KEY_SPEC_REQUESTOR_KEYRING -8 /* - key ID for request_key() dest keyring */
#define KEY_SPEC_BPF_KEYRING -9 /* - key ID for the BPF-specific keyring */
+#define KEY_SPEC_DM_VERITY_KEYRING -10 /* - key ID for the .dm-verity keyring */
+#define KEY_SPEC_FS_VERITY_KEYRING -11 /* - key ID for the .fs-verity keyring */
/* request-key default keyrings */
#define KEY_REQKEY_DEFL_NO_CHANGE -1
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index cf638bf1f7b9..3af71c6322af 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -25,6 +25,13 @@ static DEFINE_MUTEX(key_session_mutex);
/* BPF keyring reachable through KEY_SPEC_BPF_KEYRING */
static struct key *bpf_keyring __ro_after_init;
+/* dm-verity keyring reachable through KEY_SPEC_DM_VERITY_KEYRING */
+static struct key *dm_verity_keyring;
+static DEFINE_SPINLOCK(dm_verity_keyring_lock);
+
+/* fs-verity keyring reachable through KEY_SPEC_FS_VERITY_KEYRING */
+static struct key *fs_verity_keyring __ro_after_init;
+
/* The root user's tracking struct */
struct key_user root_key_user = {
.usage = REFCOUNT_INIT(3),
@@ -606,6 +613,38 @@ void key_register_bpf_keyring(struct key *keyring)
bpf_keyring = keyring;
}
+/**
+ * key_register_dm_verity_keyring - Publish the keyring for KEY_SPEC_DM_VERITY_KEYRING
+ * @keyring: The keyring to publish, or NULL to withdraw it
+ *
+ * Make @keyring reachable by userspace through the KEY_SPEC_DM_VERITY_KEYRING
+ * special key ID, so that provisioning it does not require scraping its
+ * serial out of /proc/keys first. dm-verity can be unloaded as a module
+ * and the keyring deregistered, as such serialize access with
+ * dm_verity_keyring_lock.
+ */
+void key_register_dm_verity_keyring(struct key *keyring)
+{
+ spin_lock(&dm_verity_keyring_lock);
+ dm_verity_keyring = keyring;
+ spin_unlock(&dm_verity_keyring_lock);
+}
+EXPORT_SYMBOL_GPL(key_register_dm_verity_keyring);
+
+/**
+ * key_register_fs_verity_keyring - Publish the keyring for KEY_SPEC_FS_VERITY_KEYRING
+ * @keyring: The keyring to publish
+ *
+ * Make @keyring reachable by userspace through the KEY_SPEC_FS_VERITY_KEYRING
+ * special key ID, so that provisioning it does not require scraping its
+ * serial out of /proc/keys first. Called once, from an initcall, and never
+ * undone.
+ */
+void key_register_fs_verity_keyring(struct key *keyring)
+{
+ fs_verity_keyring = keyring;
+}
+
/*
* Look up a key ID given us by userspace with a given permissions mask to get
* the key it refers to.
@@ -765,6 +804,25 @@ try_again:
key_ref = make_key_ref(key, 0);
break;
+ case KEY_SPEC_DM_VERITY_KEYRING:
+ spin_lock(&dm_verity_keyring_lock);
+ key = dm_verity_keyring;
+ if (key)
+ __key_get(key);
+ spin_unlock(&dm_verity_keyring_lock);
+ if (!key)
+ goto error;
+ key_ref = make_key_ref(key, 0);
+ break;
+
+ case KEY_SPEC_FS_VERITY_KEYRING:
+ key = fs_verity_keyring;
+ if (!key)
+ goto error;
+ __key_get(key);
+ key_ref = make_key_ref(key, 0);
+ break;
+
default:
key_ref = ERR_PTR(-EINVAL);
if (id < 1)