Linux Documentation
 help / color / mirror / Atom feed
From: Chuck Lever <cel@kernel.org>
To: Trond Myklebust <trondmy@kernel.org>,
	Anna Schumaker <anna@kernel.org>,
	 "David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	 Jakub Kicinski <kuba@kernel.org>,
	Paolo Abeni <pabeni@redhat.com>,  Simon Horman <horms@kernel.org>,
	Jonathan Corbet <corbet@lwn.net>,
	 Shuah Khan <skhan@linuxfoundation.org>,
	 Randy Dunlap <rdunlap@infradead.org>,
	 Christian Brauner <brauner@kernel.org>,
	David Howells <dhowells@redhat.com>,
	 Sagi Grimberg <sagi@grimberg.me>
Cc: linux-nfs@vger.kernel.org, keyrings@vger.kernel.org,
	 kernel-tls-handshake@lists.linux.dev, netdev@vger.kernel.org,
	 linux-doc@vger.kernel.org, Chuck Lever <cel@kernel.org>
Subject: [PATCH RFC v2 2/5] NFS: allocate the .nfs keyring per network namespace
Date: Fri, 25 Sep 2026 15:16:24 -0400	[thread overview]
Message-ID: <20260925-nfs-mtls-identity-v2-2-aa3ad17dd6c8@kernel.org> (raw)
In-Reply-To: <20260925-nfs-mtls-identity-v2-0-aa3ad17dd6c8@kernel.org>

Commit 87268f7a4f1f ("nfs: create a kernel keyring") allocates one
.nfs keyring at module load, and nothing in the NFS client reads it.
One module-wide keyring also cannot isolate x.509 credentials
between network namespaces. Each tlshd instance services the
handshake socket of one network namespace, so a credential
provisioned for that namespace's mounts has to be reachable by that
tlshd and by no other.

Allocate one .nfs keyring per network namespace in nfs_net_init()
and release it in nfs_net_exit(). tlshd finds a keyring by name
through /proc/keys, which is not namespace scoped, so each handshake
request has to carry the keyring serial number instead. Allocate
the keyring under a kernel credential rather than that of the task
creating the namespace, so an LSM labels every namespace's keyring
the same way.

The keyring grants its owner every permission and everyone else
none. Make the owner of the network namespace's user namespace the
keyring's owner, so that in a container with its own user namespace
the container's root can provision the keyring and its tlshd can
link it.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 fs/nfs/inode.c | 83 ++++++++++++++++++++++++++++++++--------------------------
 fs/nfs/netns.h |  2 ++
 2 files changed, 48 insertions(+), 37 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 832923be43a9..2b494fa5ecc0 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -2641,11 +2641,52 @@ static int nfsiod_start(void)
 unsigned int nfs_net_id;
 EXPORT_SYMBOL_GPL(nfs_net_id);
 
+#ifdef CONFIG_KEYS
+static int nfs_init_keyring(struct net *net)
+{
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct cred *cred;
+	struct key *keyring;
+
+	cred = prepare_kernel_cred(&init_task);
+	if (!cred)
+		return -ENOMEM;
+	keyring = keyring_alloc(".nfs", net->user_ns->owner,
+				net->user_ns->group, cred,
+				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				(KEY_USR_ALL & ~KEY_USR_SETATTR),
+				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
+	put_cred(cred);
+	if (IS_ERR(keyring))
+		return PTR_ERR(keyring);
+	nn->nfs_keyring = keyring;
+	return 0;
+}
+
+static void nfs_exit_keyring(struct nfs_net *nn)
+{
+	key_put(nn->nfs_keyring);
+}
+#else
+static inline int nfs_init_keyring(struct net *net)
+{
+	return 0;
+}
+
+static inline void nfs_exit_keyring(struct nfs_net *nn)
+{
+}
+#endif /* CONFIG_KEYS */
+
 static int nfs_net_init(struct net *net)
 {
 	struct nfs_net *nn = net_generic(net, nfs_net_id);
 	int err;
 
+	err = nfs_init_keyring(net);
+	if (err)
+		return err;
+
 	nfs_clients_init(net);
 
 	if (!rpc_proc_register(net, &nn->rpcstats)) {
@@ -2663,14 +2704,18 @@ static int nfs_net_init(struct net *net)
 	rpc_proc_unregister(net, "nfs");
 err_proc_rpc:
 	nfs_clients_exit(net);
+	nfs_exit_keyring(nn);
 	return err;
 }
 
 static void nfs_net_exit(struct net *net)
 {
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+
 	rpc_proc_unregister(net, "nfs");
 	nfs_fs_proc_net_exit(net);
 	nfs_clients_exit(net);
+	nfs_exit_keyring(nn);
 }
 
 static struct pernet_operations nfs_net_ops = {
@@ -2680,35 +2725,6 @@ static struct pernet_operations nfs_net_ops = {
 	.size = sizeof(struct nfs_net),
 };
 
-#ifdef CONFIG_KEYS
-static struct key *nfs_keyring;
-
-static int __init nfs_init_keyring(void)
-{
-	nfs_keyring = keyring_alloc(".nfs",
-			     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
-			     current_cred(),
-			     (KEY_POS_ALL & ~KEY_POS_SETATTR) |
-			     (KEY_USR_ALL & ~KEY_USR_SETATTR),
-			     KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
-	return PTR_ERR_OR_ZERO(nfs_keyring);
-}
-
-static void nfs_exit_keyring(void)
-{
-	key_put(nfs_keyring);
-}
-#else
-static inline int nfs_init_keyring(void)
-{
-	return 0;
-}
-
-static inline void nfs_exit_keyring(void)
-{
-}
-#endif /* CONFIG_KEYS */
-
 /*
  * Initialize NFS
  */
@@ -2716,13 +2732,9 @@ static int __init init_nfs_fs(void)
 {
 	int err;
 
-	err = nfs_init_keyring();
-	if (err)
-		return err;
-
 	err = nfs_sysfs_init();
 	if (err < 0)
-		goto err_keyring;
+		return err;
 
 	err = register_pernet_subsys(&nfs_net_ops);
 	if (err < 0)
@@ -2779,8 +2791,6 @@ static int __init init_nfs_fs(void)
 	unregister_pernet_subsys(&nfs_net_ops);
 err_sysfs:
 	nfs_sysfs_exit();
-err_keyring:
-	nfs_exit_keyring();
 	return err;
 }
 
@@ -2796,7 +2806,6 @@ static void __exit exit_nfs_fs(void)
 	nfs_fs_proc_exit();
 	nfsiod_stop();
 	nfs_sysfs_exit();
-	nfs_exit_keyring();
 }
 
 /* Not quite true; I just maintain it */
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
index 36658579100d..da0854510404 100644
--- a/fs/nfs/netns.h
+++ b/fs/nfs/netns.h
@@ -16,6 +16,7 @@ struct bl_dev_msg {
 	uint32_t major, minor;
 };
 
+struct key;
 struct nfs_netns_client;
 
 struct nfs_net {
@@ -36,6 +37,7 @@ struct nfs_net {
 #endif /* CONFIG_NFS_V4 */
 	struct nfs_netns_client *nfs_client;
 	spinlock_t nfs_client_lock;
+	struct key *nfs_keyring;
 	ktime_t boot_time;
 	struct rpc_stat rpcstats;
 #ifdef CONFIG_PROC_FS

-- 
2.55.0


  parent reply	other threads:[~2026-09-25 19:16 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-25 19:16 [PATCH RFC v2 0/5] NFS: isolate mTLS client credentials by network namespace Chuck Lever
2026-09-25 19:16 ` [PATCH RFC v2 1/5] NFS: name the init_nfs_fs() error labels Chuck Lever
2026-09-25 19:16 ` Chuck Lever [this message]
2026-09-25 19:16 ` [PATCH RFC v2 3/5] SUNRPC: pass a keyring serial number to the TLS handshake Chuck Lever
2026-09-25 19:16 ` [PATCH RFC v2 4/5] NFS: name the namespace .nfs keyring in the x509 handshake Chuck Lever
2026-09-25 19:16 ` [PATCH RFC v2 5/5] NFS: add a key type that reveals the namespace .nfs keyring serial number Chuck Lever

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260925-nfs-mtls-identity-v2-2-aa3ad17dd6c8@kernel.org \
    --to=cel@kernel.org \
    --cc=anna@kernel.org \
    --cc=brauner@kernel.org \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=dhowells@redhat.com \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kernel-tls-handshake@lists.linux.dev \
    --cc=keyrings@vger.kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=rdunlap@infradead.org \
    --cc=sagi@grimberg.me \
    --cc=skhan@linuxfoundation.org \
    --cc=trondmy@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox