From b64d21116374688c33302a6704387c27d1156d72 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 13 Sep 2026 12:07:06 -0400 Subject: [PATCH] sunrpc: pin gss module across auth_domain RCU free A gss auth_domain stores a raw pointer to svcauthops_gss in dom->flavour, and its release queues svcauth_gss_domain_release_rcu() via call_rcu(). Both live in auth_rpcgss.ko text, and nothing pins the module while a domain referencing it is reachable. rmmod auth_rpcgss can therefore unmap that text while an NFSD export still holds a reference to the domain. The export cache is one such holder. When the export is finally released, the domain reference drops from module text: svc_export_put() auth_domain_put(exp->ex_client) auth_domain_release() dom->flavour->domain_release(dom) /* into module text */ svcauth_gss_domain_release() call_rcu(&dom->rcu_head, svcauth_gss_domain_release_rcu) Once auth_rpcgss is unloaded, the domain_release call lands in unmapped memory. The rcu_barrier() in exit_rpcsec_gss() does not help: it waits only for callbacks already queued, and this one is not queued until the export goes away. NFSD's NFSv4 objects import symbols from auth_rpcgss.ko, so only a server built without CONFIG_NFSD_V4 can unload auth_rpcgss while exports still name a gss domain. Take a module reference in svcauth_gss_register_pseudoflavor() before publishing the domain and drop it at the end of svcauth_gss_domain_release_rcu(). The rcu_barrier() then holds the module image until this callback has returned. Fixes: 608a0ab2f54a ("SUNRPC: Add lockless lookup of the server's auth domain") Cc: stable@vger.kernel.org Assisted-by: kres:claude-opus-4-7 Signed-off-by: Chris Mason [ cel: rewrote description ] Link: https://patch.msgid.link/20260913160706.384180-1-cel@kernel.org Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- net/sunrpc/auth_gss/svcauth_gss.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index b319c4423d78..43839e805531 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -824,12 +824,18 @@ svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) new->h.flavour = &svcauthops_gss; new->pseudoflavor = pseudoflavor; + if (!try_module_get(svcauthops_gss.owner)) { + stat = -ENODEV; + goto out_free_name; + } + test = auth_domain_lookup(name, &new->h); if (test != &new->h) { pr_warn("svc: duplicate registration of gss pseudo flavour %s.\n", name); stat = -EADDRINUSE; auth_domain_put(test); + module_put(svcauthops_gss.owner); goto out_free_name; } return test; @@ -2004,9 +2010,11 @@ svcauth_gss_domain_release_rcu(struct rcu_head *head) { struct auth_domain *dom = container_of(head, struct auth_domain, rcu_head); struct gss_domain *gd = container_of(dom, struct gss_domain, h); + struct module *owner = dom->flavour->owner; kfree(dom->name); kfree(gd); + module_put(owner); } static void