From nobody Sun Jun 14 07:35:29 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5C043CE481; Fri, 1 May 2026 14:51:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647091; cv=none; b=tUlClu7VE0B3X4ZFCwd9MoM2RdbfiHVSXthTmaY1qlfILYIv9adjVHhGlyAy6AsPqB6ONrA5R0uT0Ynq73pdXclloNdUc5pyjOJZCpUAlGAf88kugHYCEJX70VqhHJIQE+9D31a2QjUpxzEbO/LPzYv98suBP2LI9tIVMdMEsbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647091; c=relaxed/simple; bh=UyZE3O+9MTuD6JawcvrDlgaUs2SG0Plb41/mQ0fmVC0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=plOkBxb2liZsSSeahFqvUTf7d1jN1ln4KvLDk8KF9eBefOsPt9OACJ6J1vAjrsDWykqcWMVE7iFIidoYyF44kqBmEitTdgOMElMOYLW05Nb171IQzaqF2keHP+ZCypTC+8jWQxgnm5qEj6WD2nxyWJ2D8v5S3pNLDuRc9zV4+YY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=m0Y3S2gG; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="m0Y3S2gG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4D09EC2BCC7; Fri, 1 May 2026 14:51:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777647091; bh=UyZE3O+9MTuD6JawcvrDlgaUs2SG0Plb41/mQ0fmVC0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=m0Y3S2gGP/IJ5IlZ3aDVy/ycqYcXYP54jUw3sUwJKDrOfjd7J8Aq9YGWwqazzjblK SKigYSNgS5+q0q0ZFDokXiaJ01iLtj+FU2NppQw8ofVZ84GQecYMP8fnVWJ7/Q5Ckt nN0UowlD8xIFE52hIs5w2HvXOeU3+Kd79hR1ikMqATNqEEfs28OhICbEofVD9EVLpp /U9nMnLTxg1S0fBOB9PH2xkHr6emoClo5jIMrzUWdRTm9ufvqbzyVwpg/dYDk+zmOo ksxe1n2pRKuJY+z9LDAC9YAogGdOo3HkQpIImwerYvQP2Exrl+WPMS/9TsUzVfK+yV R/X/AyQ0bQz6g== From: Chuck Lever Date: Fri, 01 May 2026 10:51:07 -0400 Subject: [PATCH 1/6] SUNRPC: Move cache_initialize() declaration to sunrpc-private header Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260501-cache-uaf-fix-v1-1-a49928bf4817@oracle.com> References: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> In-Reply-To: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> To: Misbah Anjum N , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Yang Erkun Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Chuck Lever X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2485; i=chuck.lever@oracle.com; h=from:subject:message-id; bh=f19g8gb4ZDllUEQ/XuyKLXf2ZZo6fSjdCzNFYP7WVJE=; b=owEBbQKS/ZANAwAKATNqszNvZn+XAcsmYgBp9L3w5haD4o1Scu4q1iIt+VXHRWISVGaFz6XXb +jtCyfhD2KJAjMEAAEKAB0WIQQosuWwEobfJDzyPv4zarMzb2Z/lwUCafS98AAKCRAzarMzb2Z/ lwL5D/9M+8LTwFG384Y2eqTq6x6iMV1DdLAGoJa4au0OUwOmkvPNKlIb/QGiuScR0R+cNFtIFQz /2zOdPaV/dsU/rkS2I4SQY1jywdOGiathwwBuJHGedNw+MPc1lFfmfX9MLSRhgTNFehxdHhl/5l 6Dohzcq0wfJzPM21W+kepfC1SvCnCS3U1Vqvq03xnGtSpUhYenHrs64kA+XGA0U6MB2XCQr9xCa hbDAjj4/KFg7kNE2ptnkTzXAXWPk6AoQme641LyyDuCBEs9Zk1kGQWC/VPvDOr2e/nYOo3UTWJ6 xm9Sk1oAqzhIXIuB32Md8TaSE2mfd5b554H1bf2oF9gzZuqtcHOfJWYr5ElTzSLZQZTKG3Cmzz1 9fvqciOVeBPnxfn4zWQIzF+6wDffAUTEPvL4e7YFeiQAHcG62WQ92xoCbDCmx7ryzmda29PmP1/ S425vIs5Zp49P67s+gDSdaVQs88HO23w+HZtJNQddg0OsReDw0YRGQgJdmP95G32xSjDpMaLQ34 l6eZuuajKmCchmazoAWs7Pkfesu9jOswGbzLGUhB8Uo8ao8Mu3cddgC5zliV8v9CEnc4a4rIGqx xDbDJYXlaP62JqZey+bUxAphwmL+VzB+Tu1DoBhpTaj4kODefjd13yg+KZ24gQ6BQ7x5W0hzCG+ KVet6Clar2GqxvA== X-Developer-Key: i=chuck.lever@oracle.com; a=openpgp; fpr=28B2E5B01286DF243CF23EFE336AB3336F667F97 From: Chuck Lever cache_initialize() was introduced by commit 8eab945c5616 ("sunrpc: make the cache cleaner workqueue deferrable", 2010) and placed in the public include/linux/sunrpc/cache.h from the start, but it has never been EXPORT_SYMBOL_GPL'd. The only caller, init_sunrpc() in net/sunrpc/sunrpc_syms.c, is built into the same module that defines the function, so external modules could not link against the symbol even if they tried. The public declaration has been a stale-public hygiene leak ever since. Relocate the declaration to net/sunrpc/sunrpc.h alongside other sunrpc-internal helpers and include that header from net/sunrpc/cache.c so the compiler enforces prototype consistency at the definition site. The public include/linux/sunrpc/cache.h now reflects the actual external API surface. No functional change. Assisted-by: Claude:claude-opus-4-7[1m] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Tested-by: Alexandr Alexandrov --- include/linux/sunrpc/cache.h | 1 - net/sunrpc/cache.c | 1 + net/sunrpc/sunrpc.h | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 2735c332ddb7..83c88dc82e69 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -237,7 +237,6 @@ extern int cache_check(struct cache_detail *detail, extern void cache_flush(void); extern void cache_purge(struct cache_detail *detail); #define NEVER (0x7FFFFFFF) -extern void __init cache_initialize(void); extern int cache_register_net(struct cache_detail *cd, struct net *net); extern void cache_unregister_net(struct cache_detail *cd, struct net *net); =20 diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 391037f15292..488a14961b19 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -39,6 +39,7 @@ #include "netns.h" #include "netlink.h" #include "fail.h" +#include "sunrpc.h" =20 #define RPCDBG_FACILITY RPCDBG_CACHE =20 diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index e3c6e3b63f0b..7fa35ee8f9a4 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -41,6 +41,7 @@ struct svc_rqst; int rpc_clients_notifier_register(void); void rpc_clients_notifier_unregister(void); void auth_domain_cleanup(void); +void __init cache_initialize(void); void svc_sock_update_bufs(struct svc_serv *serv); enum svc_auth_status svc_authenticate(struct svc_rqst *rqstp); #endif /* _NET_SUNRPC_SUNRPC_H */ --=20 2.53.0 From nobody Sun Jun 14 07:35:29 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E99A3CD8C5; Fri, 1 May 2026 14:51:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647093; cv=none; b=DGbl+NFzo35Kd8YIdksXLTQ5H1g1KisMZQABwgdv3FYlU5coKdl060fa7swdHk9D+aF/fNRjPZjt4eTBCad2a3BMmC3ZRw/sLzzi7wFamVtI095O1Ue/rWTuZDgwnu4a0jxs+00KTa57wt40eW9pj18ud/0xLjayRIiXur+cLMw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647093; c=relaxed/simple; bh=69P2lg2IQFIB3BrQK9DHI+1pCthUqibNJZ9MINjaf1s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dx8AWwd/HtTP5N5WQfoN3IhvzDe3kOYmfNZkN4JCuqOHRaRvxLeFyFQSrTbNPpNqyuKvndV8xifAcWLpPzdeZLbEne6OnSl12dmOkUoDQWhHXD6K/WFSZf6kcXbwkZm44M3CkOGPR3mBtWebdZJRU7+qIi8d4aRZn0JtIc1ot1c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Kd92EvE6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Kd92EvE6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B3E60C2BCB4; Fri, 1 May 2026 14:51:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777647093; bh=69P2lg2IQFIB3BrQK9DHI+1pCthUqibNJZ9MINjaf1s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Kd92EvE62SRmaGLkCl8WPFJKZG10lsuzZ9GVcilm56u9g+rbqmWirooK+pstBc2FZ OXbMNqpBPxHaRNodIkK5kil/ubU4Uk9aXMtksZxWbH8EE5tGyoHUjIENEF22V9gjUG BX1hfnshlFFHQTxvSyCvWlNOljbitXGuJhLuyjFlfGuxrOcjU/hnQY3i5IiyR952q/ aTJw/SNiSBS1z0Tyzoowd3OzEAuWSw5EnMfFSgklzO57BSWzjbbvKPf1r5siz5OWxN 4h+kToxiHhZiIo00MuRxWDPdeqGBxF88zxgLGMqmsCOD0moaAb7KHnwH7J9bpTMU7K c3GkXQQ05kVRQ== From: Chuck Lever Date: Fri, 01 May 2026 10:51:08 -0400 Subject: [PATCH 2/6] SUNRPC: Provide a shared workqueue for cache release callbacks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260501-cache-uaf-fix-v1-2-a49928bf4817@oracle.com> References: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> In-Reply-To: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> To: Misbah Anjum N , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Yang Erkun Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Chuck Lever X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=11862; i=chuck.lever@oracle.com; h=from:subject:message-id; bh=mPDAInV4wOnabNaiev670wLI8X52Ubl1nQ3gDsI7Ua8=; b=owEBbQKS/ZANAwAKATNqszNvZn+XAcsmYgBp9L3wB/cbkWCN1rTjHBsvSpYNqHB1X1OQUxGih 4P58v2qFdyJAjMEAAEKAB0WIQQosuWwEobfJDzyPv4zarMzb2Z/lwUCafS98AAKCRAzarMzb2Z/ l0HxD/48WphoeFNBdtdtTR2Xu1m2NmPogAapwmdleajZ9d50485FtJBEBABMQfsusCWiT/aul7U wtrsafYNGC1CjINnV8TmS0RFDoQMfkRx62j3jgfst5A3994BivfcAVJ/37mjrRIPKfySAiADmJe DXJRTuqhEkQub3iTMXt2FYfe6vMLD7Yj7LrtgYdKalHfqnwGpRMWmf1sI4gsgpoWXV4WAl+GUD3 G19JVpXNUzAjxg6mvlXp2bkXtO2bKo+Jem4Sj11zeYFQB1AtvaZ20PtTVSRnim6JGsjVIfGB+9i 8p0xSCaT/CLS8Xn5J1u1FM1PSNaVS0I/XH1qb8yG28uEiZjojRaxE/1LDw9vNWgOL57TvTLyr2X voGCTlzkmVISvNMSyYtsaxu655wXx7Koo5PasECT148iRGyoJBAqhClC5q8wE+nIUY4oWdjgH1P TnjLF3nwi+6KYHqKvOOxYXcQMekHHPF1r4Br7nrRrRW0MZRYZ3O+q8vPmsUsu3flpfHBK/1eSJh Y+XXqh5PLuRY1KjYOzzd1J8EYG0ftdGRAq9mmUoZpwyIeuFuO3dQmbIFk18z+ctUpd+/wwwCKPa kTQB1HVr4Qgq6p+TcPlHah2VbV2xkIzT/56Z1BRqlzxN4EDqo06oflcnOP64iRcmaMhmOaHO6FH CDVg2q9Ben/bMJA== X-Developer-Key: i=chuck.lever@oracle.com; a=openpgp; fpr=28B2E5B01286DF243CF23EFE336AB3336F667F97 From: Chuck Lever Cache .put callbacks may need to release sub-objects whose cleanup sleeps (path_put, auth_domain_put, put_group_info), which precludes running the release from a call_rcu() softirq callback. Commit 48db892356d6 ("NFSD: Defer sub-object cleanup in export put callbacks") introduced nfsd_export_wq for that purpose, with a dedicated workqueue chosen so that flush_workqueue() in the per-namespace teardown path drains only NFSD export release work rather than blocking on unrelated work queued to system_unbound_wq. Subsequent patches in this series convert the sunrpc ip_map and unix_gid put callbacks to the same queue_rcu_work() pattern, and those would otherwise need their own per-cache workqueue for the same reason. Hoist the workqueue up to the sunrpc layer so that all four cache_detail put callbacks share a single workqueue, managed entirely within net/sunrpc/cache.c. Expose the workqueue through three helpers. sunrpc_cache_queue_release() schedules a deferred release after the next RCU grace period. sunrpc_cache_destroy_net() encapsulates the cache_unregister_net() + drain + cache_destroy_net() sequence that single-cache teardowns otherwise have to open-code, putting the ordering rule in one place. sunrpc_cache_drain() exposes the underlying rcu_barrier() + flush_workqueue() primitive for the rare caller that drains multiple cache_details together, such as nfsd_export_shutdown(). Allocate the workqueue in cache_initialize() and destroy it in a new cache_destroy() called from cleanup_sunrpc(). Replace the local nfsd_export_wq with the shared sunrpc helpers and drop the nfsd_export_wq_init/shutdown helpers and their callers. Assisted-by: Claude:claude-opus-4-7[1m] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Tested-by: Alexandr Alexandrov --- fs/nfsd/export.c | 41 +++----------------------- fs/nfsd/export.h | 2 -- fs/nfsd/nfsctl.c | 8 +---- include/linux/sunrpc/cache.h | 3 ++ net/sunrpc/cache.c | 70 ++++++++++++++++++++++++++++++++++++++++= +++- net/sunrpc/sunrpc.h | 3 +- net/sunrpc/sunrpc_syms.c | 23 +++++++++------ 7 files changed, 93 insertions(+), 57 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 15972919e1e9..3c4340e743fa 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -39,8 +39,6 @@ * second map contains a reference to the entry in the first map. */ =20 -static struct workqueue_struct *nfsd_export_wq; - #define EXPKEY_HASHBITS 8 #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) @@ -62,7 +60,7 @@ static void expkey_put(struct kref *ref) struct svc_expkey *key =3D container_of(ref, struct svc_expkey, h.ref); =20 INIT_RCU_WORK(&key->ek_rwork, expkey_release); - queue_rcu_work(nfsd_export_wq, &key->ek_rwork); + sunrpc_cache_queue_release(&key->ek_rwork); } =20 static int expkey_upcall(struct cache_detail *cd, struct cache_head *h) @@ -652,7 +650,7 @@ static void svc_export_put(struct kref *ref) struct svc_export *exp =3D container_of(ref, struct svc_export, h.ref); =20 INIT_RCU_WORK(&exp->ex_rwork, svc_export_release); - queue_rcu_work(nfsd_export_wq, &exp->ex_rwork); + sunrpc_cache_queue_release(&exp->ex_rwork); } =20 /** @@ -2193,36 +2191,6 @@ const struct seq_operations nfs_exports_op =3D { .show =3D e_show, }; =20 -/** - * nfsd_export_wq_init - allocate the export release workqueue - * - * Called once at module load. The workqueue runs deferred svc_export and - * svc_expkey release work scheduled by queue_rcu_work() in the cache put - * callbacks. - * - * Return values: - * %0: workqueue allocated - * %-ENOMEM: allocation failed - */ -int nfsd_export_wq_init(void) -{ - nfsd_export_wq =3D alloc_workqueue("nfsd_export", WQ_UNBOUND, 0); - if (!nfsd_export_wq) - return -ENOMEM; - return 0; -} - -/** - * nfsd_export_wq_shutdown - drain and free the export release workqueue - * - * Called once at module unload. Per-namespace teardown in - * nfsd_export_shutdown() has already drained all deferred work. - */ -void nfsd_export_wq_shutdown(void) -{ - destroy_workqueue(nfsd_export_wq); -} - /* * Initialize the exports module. */ @@ -2284,9 +2252,8 @@ nfsd_export_shutdown(struct net *net) =20 cache_unregister_net(nn->svc_expkey_cache, net); cache_unregister_net(nn->svc_export_cache, net); - /* Drain deferred export and expkey release work. */ - rcu_barrier(); - flush_workqueue(nfsd_export_wq); + /* One drain covers both caches' deferred release work. */ + sunrpc_cache_drain(); cache_destroy_net(nn->svc_expkey_cache, net); cache_destroy_net(nn->svc_export_cache, net); svcauth_unix_purge(net); diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h index b05399374574..8969e81de448 100644 --- a/fs/nfsd/export.h +++ b/fs/nfsd/export.h @@ -111,8 +111,6 @@ __be32 check_nfsd_access(struct svc_export *exp, struct= svc_rqst *rqstp, /* * Function declarations */ -int nfsd_export_wq_init(void); -void nfsd_export_wq_shutdown(void); int nfsd_export_init(struct net *); void nfsd_export_shutdown(struct net *); void nfsd_export_flush(struct net *); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 064a2e749bc9..468aad8c3af9 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -2536,12 +2536,9 @@ static int __init init_nfsd(void) if (retval) goto out_free_pnfs; nfsd_lockd_init(); /* lockd->nfsd callbacks */ - retval =3D nfsd_export_wq_init(); - if (retval) - goto out_free_lockd; retval =3D register_pernet_subsys(&nfsd_net_ops); if (retval < 0) - goto out_free_export_wq; + goto out_free_lockd; retval =3D register_cld_notifier(); if (retval) goto out_free_subsys; @@ -2570,8 +2567,6 @@ static int __init init_nfsd(void) unregister_cld_notifier(); out_free_subsys: unregister_pernet_subsys(&nfsd_net_ops); -out_free_export_wq: - nfsd_export_wq_shutdown(); out_free_lockd: nfsd_lockd_shutdown(); nfsd_drc_slab_free(); @@ -2592,7 +2587,6 @@ static void __exit exit_nfsd(void) nfsd4_destroy_laundry_wq(); unregister_cld_notifier(); unregister_pernet_subsys(&nfsd_net_ops); - nfsd_export_wq_shutdown(); nfsd_drc_slab_free(); nfsd_lockd_shutdown(); nfsd4_free_slabs(); diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 83c88dc82e69..84802438a5fc 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -237,11 +237,14 @@ extern int cache_check(struct cache_detail *detail, extern void cache_flush(void); extern void cache_purge(struct cache_detail *detail); #define NEVER (0x7FFFFFFF) +extern void sunrpc_cache_queue_release(struct rcu_work *rwork); +extern void sunrpc_cache_drain(void); extern int cache_register_net(struct cache_detail *cd, struct net *net); extern void cache_unregister_net(struct cache_detail *cd, struct net *net); =20 extern struct cache_detail *cache_create_net(const struct cache_detail *tm= pl, struct net *net); extern void cache_destroy_net(struct cache_detail *cd, struct net *net); +extern void sunrpc_cache_destroy_net(struct cache_detail *cd, struct net *= net); =20 extern void sunrpc_init_cache_detail(struct cache_detail *cd); extern void sunrpc_destroy_cache_detail(struct cache_detail *cd); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 488a14961b19..733bcd3daa46 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1705,9 +1705,77 @@ static int create_cache_proc_entries(struct cache_de= tail *cd, struct net *net) return -ENOMEM; } =20 -void __init cache_initialize(void) +static struct workqueue_struct *sunrpc_cache_wq; + +/** + * sunrpc_cache_queue_release - schedule deferred cache release work + * @rwork: caller-initialized rcu_work to queue + * + * Run @rwork in process context after the next RCU grace period. + * Use this for cache .put callbacks whose cleanup may sleep + * (path_put(), auth_domain_put()). + */ +void sunrpc_cache_queue_release(struct rcu_work *rwork) { + queue_rcu_work(sunrpc_cache_wq, rwork); +} +EXPORT_SYMBOL_GPL(sunrpc_cache_queue_release); + +/** + * sunrpc_cache_drain - drain pending cache release work + * + * Wait for outstanding RCU callbacks to enqueue their release + * work, then flush that work to completion. + */ +void sunrpc_cache_drain(void) +{ + rcu_barrier(); + flush_workqueue(sunrpc_cache_wq); +} +EXPORT_SYMBOL_GPL(sunrpc_cache_drain); + +/** + * sunrpc_cache_destroy_net - quiesce and tear down a per-net cache + * @cd: the cache_detail to release + * @net: the network namespace owning @cd + * + * Canonical teardown for caches whose .put callbacks use + * sunrpc_cache_queue_release(). Unregister @cd to stop new + * lookups, drain in-flight RCU callbacks and queued release + * work, then free @cd and its hash table. The drain ensures + * release workers complete while the cache_detail is still + * valid. + */ +void sunrpc_cache_destroy_net(struct cache_detail *cd, struct net *net) +{ + cache_unregister_net(cd, net); + sunrpc_cache_drain(); + cache_destroy_net(cd, net); +} +EXPORT_SYMBOL_GPL(sunrpc_cache_destroy_net); + +/** + * cache_initialize - allocate sunrpc cache subsystem resources + */ +int __init cache_initialize(void) +{ + sunrpc_cache_wq =3D alloc_workqueue("sunrpc_cache", + WQ_UNBOUND | WQ_MEM_RECLAIM, 0); + if (!sunrpc_cache_wq) + return -ENOMEM; INIT_DEFERRABLE_WORK(&cache_cleaner, do_cache_clean); + return 0; +} + +/** + * cache_destroy - release sunrpc cache subsystem resources + * + * Caller must ensure no further sunrpc_cache_queue_release() + * calls can be scheduled before invoking this. + */ +void cache_destroy(void) +{ + destroy_workqueue(sunrpc_cache_wq); } =20 int cache_register_net(struct cache_detail *cd, struct net *net) diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 7fa35ee8f9a4..75ee201e4800 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -41,7 +41,8 @@ struct svc_rqst; int rpc_clients_notifier_register(void); void rpc_clients_notifier_unregister(void); void auth_domain_cleanup(void); -void __init cache_initialize(void); +int __init cache_initialize(void); +void cache_destroy(void); void svc_sock_update_bufs(struct svc_serv *serv); enum svc_auth_status svc_authenticate(struct svc_rqst *rqstp); #endif /* _NET_SUNRPC_SUNRPC_H */ diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index ab88ce46afb5..d75ff1e592f2 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -97,24 +97,26 @@ init_sunrpc(void) if (err) goto out2; =20 - cache_initialize(); - - err =3D register_pernet_subsys(&sunrpc_net_ops); + err =3D cache_initialize(); if (err) goto out3; =20 - err =3D register_rpc_pipefs(); + err =3D register_pernet_subsys(&sunrpc_net_ops); if (err) goto out4; =20 - err =3D rpc_sysfs_init(); + err =3D register_rpc_pipefs(); if (err) goto out5; =20 - err =3D genl_register_family(&sunrpc_nl_family); + err =3D rpc_sysfs_init(); if (err) goto out6; =20 + err =3D genl_register_family(&sunrpc_nl_family); + if (err) + goto out7; + sunrpc_debugfs_init(); #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) rpc_register_sysctl(); @@ -123,12 +125,14 @@ init_sunrpc(void) init_socket_xprt(); /* clnt sock transport */ return 0; =20 -out6: +out7: rpc_sysfs_exit(); -out5: +out6: unregister_rpc_pipefs(); -out4: +out5: unregister_pernet_subsys(&sunrpc_net_ops); +out4: + cache_destroy(); out3: rpcauth_remove_module(); out2: @@ -157,6 +161,7 @@ cleanup_sunrpc(void) rpc_unregister_sysctl(); #endif rcu_barrier(); /* Wait for completion of call_rcu()'s */ + cache_destroy(); } MODULE_DESCRIPTION("Sun RPC core"); MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Sun Jun 14 07:35:29 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2AD2A3CCFB0; Fri, 1 May 2026 14:51:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647096; cv=none; b=oNygRyy0EPATEFZ5X4jmyl61PeW0sNGnQf9yaPiqs14myBKO3bH+KK3xd2bg4OQhKyZpYElGlirqyDyypYY4JdYs0hJHd/8EFhWPGC12/h0uA9OssFk8AqEv3G29wa4N4EZgp9/uZPpMr+xcSQHvz2P7Is0a7lwJGK/abA2Dp50= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647096; c=relaxed/simple; bh=uTVfM0ocfHbzm/p/1pxNJ122SwRDL801DcpPT5VWWkA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MR4rpQYwqA0NH1+zSQjhjTnCd+j/vMB4Jh3RXO5iBWb79yLVAU7dcvRVQgf/WDXrcaP7p0096F8D6Y0zEX7m/3En0vT5vh7ye//mp5yu7+kC5snN59+XiISn+aBjnNo+02cwMxqIb5iWbkV6d3rXeyzyqclanyvNos6pt3msNr4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SDa2/pg8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SDa2/pg8" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2B074C4AF09; Fri, 1 May 2026 14:51:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777647094; bh=uTVfM0ocfHbzm/p/1pxNJ122SwRDL801DcpPT5VWWkA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=SDa2/pg8+4c1D7pAoHN1Vv4Hz1SrYnzeKbyBZpQiZDALKDVMwE1vCy8XJBmO2E+8b znemji3tK7t/gXY7f2XhDcYPcff3f0yXZDcQYKcyvYbRBljfpqykRUHOy6bYVYkOTL 0bu3ppiDoUHtT9yaXLFwswoWlcI35fzf9iBgoNnHXBQ95emctOu5H/AaCf0MB/B+E/ jXrpo4f6H/dy7CYlXRGaUhU1XJ9oekPkDNm56AtvqE2GBBPLjWIB0mzjVf1WgxiOMG UkKPoFSOHJBmKv0BKMdEsUqrfwiRxfKAAqd6CP+dQRI6tDK/xxt7iKbopbNp2dJOmu 1RnPmSx7td9zw== From: Chuck Lever Date: Fri, 01 May 2026 10:51:09 -0400 Subject: [PATCH 3/6] SUNRPC: Defer ip_map sub-object cleanup past RCU grace period Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260501-cache-uaf-fix-v1-3-a49928bf4817@oracle.com> References: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> In-Reply-To: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> To: Misbah Anjum N , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Yang Erkun Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Chuck Lever X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=3103; i=chuck.lever@oracle.com; h=from:subject:message-id; bh=sb+xxxOHmR0sxCWTQowT0Yl00Gq2aGRg+yOkr62nVJc=; b=owEBbQKS/ZANAwAKATNqszNvZn+XAcsmYgBp9L3wdukcWshwWSO7EzcyK2oM5/K93QyrjUPOb Xfp/eUVPxuJAjMEAAEKAB0WIQQosuWwEobfJDzyPv4zarMzb2Z/lwUCafS98AAKCRAzarMzb2Z/ l6hvEAC5AidwWZ/9SzSuZgP8+2rI4OLcfjHaUQQDBvZdN7bG2OpriCMWAO0/N/nmmDmv2PO8khU FyYmbj5EEmVTZKRQ5fjDXGRQpb+EkHlxadiy1EqTuDpiwRV16rzZ9Nsmc31IM9oA0jzRKb3V80n 3861q6cmj2DtGZseLe9ttCQbHIx8/Nkqvuf45b0KA9v5qOZzCiyNnDy6DOTcUfu7523NxE6bIvp xQXC/UBbBKD5OracJHoKux0bY5Vqyu1PaT2beZmmMqXZL4M53JWgZ6sKz+eiIlGpEWeNphkop77 yKRR2f6WRoECdFJgKCQ7Bd7UKHC1+uYQccveJ0qQqrToMQHIEsWMlid4RgWg0STTTpqs55B/77o 3Yyk4Etgswm+3mYXKc/3Hy2bON1HcjL9yGSw+WS9+e/GqCdy1OxreF/3d68DNFT58DCT76ghMoF 9G0jB/tNkvOXh8OxNonjZxFOwbnNtbvGXoma9LZ37v9yqKrgepsTd8qSYe/kWFZ6wktCYSTxHAk Sl4JQk5FS/LB40D4Uuct2R8LV0chtQOdsJNTE9FQ6gKKcTiL5XajVPnDN5lff7+TeR8/uM9nRMb LWLPKpX90UHEC3Y1yO/tkKEO/ypUu3rZZD/r+2I/RMgv5SVD6JoiAwn3D7iC8taJH1RAJGQ1BJJ lhWXhIfEn/Zj5xg== X-Developer-Key: i=chuck.lever@oracle.com; a=openpgp; fpr=28B2E5B01286DF243CF23EFE336AB3336F667F97 From: Chuck Lever ip_map_put() is already correct in that auth_domain_put() of im->m_client reaches svcauth_unix_domain_release(), which defers the actual kfree() of the unix_domain with call_rcu(); the ip_map itself is freed via kfree_rcu(). Readers in c_show() under cache_seq_start_rcu() therefore observe both objects until the next RCU grace period. This patch is a consistency change rather than a bug fix. The svc_export and svc_expkey caches were converted to the queue_rcu_work() pattern in commit 48db892356d6 ("NFSD: Defer sub-object cleanup in export put callbacks") because path_put() and auth_domain_put() must run in process context after the RCU grace period. The next patch routes unix_gid through the same mechanism. Sending ip_map through sunrpc_cache_queue_release() unifies all four cache_detail .put callbacks on a single release path and removes the implicit reliance on every current and future auth_ops .domain_release implementation deferring its own kfree() behind call_rcu(). Replace the rcu_head field with an rcu_work, move the kfree() and auth_domain_put() into a new ip_map_release() taking a work_struct, and have ip_map_put() invoke INIT_RCU_WORK() and sunrpc_cache_queue_release() in place of kfree_rcu(). Switch ip_map_cache_destroy() to sunrpc_cache_destroy_net() so per-namespace teardown waits for outstanding release work before freeing the cache_detail. Assisted-by: Claude:claude-opus-4-7[1m] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Tested-by: Alexandr Alexandrov --- net/sunrpc/svcauth_unix.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 64a2658faddb..14688813c242 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -103,18 +103,26 @@ struct ip_map { char m_class[8]; /* e.g. "nfsd" */ struct in6_addr m_addr; struct unix_domain *m_client; - struct rcu_head m_rcu; + struct rcu_work m_rwork; }; =20 +static void ip_map_release(struct work_struct *work) +{ + struct ip_map *im =3D container_of(to_rcu_work(work), + struct ip_map, m_rwork); + + if (test_bit(CACHE_VALID, &im->h.flags) && + !test_bit(CACHE_NEGATIVE, &im->h.flags)) + auth_domain_put(&im->m_client->h); + kfree(im); +} + static void ip_map_put(struct kref *kref) { - struct cache_head *item =3D container_of(kref, struct cache_head, ref); - struct ip_map *im =3D container_of(item, struct ip_map,h); + struct ip_map *im =3D container_of(kref, struct ip_map, h.ref); =20 - if (test_bit(CACHE_VALID, &item->flags) && - !test_bit(CACHE_NEGATIVE, &item->flags)) - auth_domain_put(&im->m_client->h); - kfree_rcu(im, m_rcu); + INIT_RCU_WORK(&im->m_rwork, ip_map_release); + sunrpc_cache_queue_release(&im->m_rwork); } =20 static inline int hash_ip6(const struct in6_addr *ip) @@ -1569,6 +1577,5 @@ void ip_map_cache_destroy(struct net *net) =20 sn->ip_map_cache =3D NULL; cache_purge(cd); - cache_unregister_net(cd, net); - cache_destroy_net(cd, net); + sunrpc_cache_destroy_net(cd, net); } --=20 2.53.0 From nobody Sun Jun 14 07:35:29 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2ADB33CD8B5; Fri, 1 May 2026 14:51:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647096; cv=none; b=EZAV+b/62dTcd+GaPq+pcBDJ3/tU2mRTEfS5tTT85LxsiHHe2Hxy1ig8uka3MpWzXPJeE06BCaS/TALj2RXMzyk9P+PM6ydTHfiBv8EW9uXPPGO691EHHO0iFTMBYlEI/2DvlheBc5tZgO4GGqudORb2VDmypG4PSgsLP+iWRxU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647096; c=relaxed/simple; bh=bbS7Hvj+elJ6Hlp+4O+j+mJOOr6RrqQNSeYM+ZJAdAY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ap21FN+i3wbJvw+dWaWiGRSFLRkl0yiNu8PxT/Hrfcs1nmhKxoD7D9YDDKScFr2/K8xHFX2MdEcpVsX+d02OL3qxFIcOZEgxhoV0IFeW64jMnod5lso9UFlMYJnLoM314Eq/ofeaorkv761Blk4yv28l7C1b7oKDnyvp8sqR4TI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MQrZlQz5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MQrZlQz5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9539FC2BCB4; Fri, 1 May 2026 14:51:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777647095; bh=bbS7Hvj+elJ6Hlp+4O+j+mJOOr6RrqQNSeYM+ZJAdAY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=MQrZlQz5oH9xjNJyRcDws+4dv52mk60v30I5mNT1LcHhkH1T9qDL3oKCcRjJJ4fKX JzB319WSWosRPNq7nS+NAWmsGk2QJQO/wZcGaZcygtN9VWdVNvtPJASu0OFZrR8ksI MYT0CcD4WryIXU3o/wzCSniFs6DxjB2D+7R8Gedb0swRtKaIm/Stce4yONbE0xfL4O ovUvtNa05xodOJDIikzy0n8O6JSxaHYon/ltGiRCAIce1WRRrSI4COiMSa/bAFIPY2 ryDPaEZcy1SHnaYBUss1mHC3YFUgnOfSw2JgqaPs5G+Zfb7s5sr6y3wkR7G6Jue/HM q++0c8MnZyw2A== From: Chuck Lever Date: Fri, 01 May 2026 10:51:10 -0400 Subject: [PATCH 4/6] SUNRPC: Use shared release pattern for the unix_gid cache Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260501-cache-uaf-fix-v1-4-a49928bf4817@oracle.com> References: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> In-Reply-To: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> To: Misbah Anjum N , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Yang Erkun Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Chuck Lever X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2898; i=chuck.lever@oracle.com; h=from:subject:message-id; bh=6LhmQM+mCkrBZotHwoovj5QO/zCfh6oXMp4HfVQlhB0=; b=owEBbQKS/ZANAwAKATNqszNvZn+XAcsmYgBp9L3wnpS9Sx2etwsOFk5FodhOGOzvbtWDXfHH0 VqmEJfiTn+JAjMEAAEKAB0WIQQosuWwEobfJDzyPv4zarMzb2Z/lwUCafS98AAKCRAzarMzb2Z/ lwqRD/0YHnEn1hyeqXT1SlJa4XrFOGh0UQwjgRESQRdbU0mjwaqlFtfTWkHyLm9jkeCVUflrvG/ JIQS6Ylf+F4me2zB3/WM3uMfGksr7o6jNor7ScUx3VibcWez638VkhA8CBpUqboXCkuJJarPGEq tFBU5FXPiwAi0Pp09f8M3K28S/pt9dqxuHuDEvZbRUzMsy+twZDvDXsesam5J2n1ROc+E/fNc8k FcS/sg40/As8jFgEaLACjlEgKt0piMNwPuwyvqykkZ52PxjNz6Um6niqeqGqx89wnMJz4R0R2+K 45M4REhXQt1wWfGERFhByPDXHvxUiG7KFk9xILZC+bw1Lyr5/swCMeWKTLrhmms5eMM8VSYnSfd Kz0vVQI5ZHhXP3kSOO9w1FOZVWC6qYPT2auqQdaDSt+HySeXUIOgL+VrmuvTq7PAylKjUGpCut+ aCxwXOr6AlRZyY+DwFT8nTAYZrlmy7KmU/qRgyEtmb26CtWI6CJnTbzYO7gwdzRCFrv43zAdJsN CKnuQxUTrhjdYsU7W7kvLSKHlK7aYpBNdRIHe14rJ8dIVYDL0LPvgtouOiTZ0EGt9fFRJH1jkWc Uj0w+05VsfBGSkVzKBai7cBLuEK5eLli4Sd5UPxK2mfhHDKMGJ95DymMEKJmFUtfJ9Makve/VKp ++mRijnbbPwe3GA== X-Developer-Key: i=chuck.lever@oracle.com; a=openpgp; fpr=28B2E5B01286DF243CF23EFE336AB3336F667F97 From: Chuck Lever unix_gid_put() is already correct in that put_group_info() runs inside its call_rcu() callback, after the RCU grace period. This patch is a consistency change rather than a bug fix: the three other cache_detail .put callbacks (svc_export, svc_expkey, ip_map) now use the queue_rcu_work() pattern via sunrpc_cache_queue_release(), and routing unix_gid through the same path keeps a single release mechanism for all four caches. Replace the rcu_head field with an rcu_work, rename unix_gid_free() to unix_gid_release() and convert it to take a work_struct, and have unix_gid_put() invoke INIT_RCU_WORK() and sunrpc_cache_queue_release() in place of call_rcu(). Switch unix_gid_cache_destroy() to sunrpc_cache_destroy_net() so per-namespace teardown waits for outstanding release work before freeing the cache_detail. Assisted-by: Claude:claude-opus-4-7[1m] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Tested-by: Alexandr Alexandrov --- net/sunrpc/svcauth_unix.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 14688813c242..762cf03574b4 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -420,7 +420,7 @@ struct unix_gid { struct cache_head h; kuid_t uid; struct group_info *gi; - struct rcu_head rcu; + struct rcu_work rwork; }; =20 static int unix_gid_hash(kuid_t uid) @@ -428,23 +428,23 @@ static int unix_gid_hash(kuid_t uid) return hash_long(from_kuid(&init_user_ns, uid), GID_HASHBITS); } =20 -static void unix_gid_free(struct rcu_head *rcu) +static void unix_gid_release(struct work_struct *work) { - struct unix_gid *ug =3D container_of(rcu, struct unix_gid, rcu); - struct cache_head *item =3D &ug->h; + struct unix_gid *ug =3D container_of(to_rcu_work(work), + struct unix_gid, rwork); =20 - if (test_bit(CACHE_VALID, &item->flags) && - !test_bit(CACHE_NEGATIVE, &item->flags)) + if (test_bit(CACHE_VALID, &ug->h.flags) && + !test_bit(CACHE_NEGATIVE, &ug->h.flags)) put_group_info(ug->gi); kfree(ug); } =20 static void unix_gid_put(struct kref *kref) { - struct cache_head *item =3D container_of(kref, struct cache_head, ref); - struct unix_gid *ug =3D container_of(item, struct unix_gid, h); + struct unix_gid *ug =3D container_of(kref, struct unix_gid, h.ref); =20 - call_rcu(&ug->rcu, unix_gid_free); + INIT_RCU_WORK(&ug->rwork, unix_gid_release); + sunrpc_cache_queue_release(&ug->rwork); } =20 static int unix_gid_match(struct cache_head *corig, struct cache_head *cne= w) @@ -899,8 +899,7 @@ void unix_gid_cache_destroy(struct net *net) =20 sn->unix_gid_cache =3D NULL; cache_purge(cd); - cache_unregister_net(cd, net); - cache_destroy_net(cd, net); + sunrpc_cache_destroy_net(cd, net); } =20 static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t ui= d) --=20 2.53.0 From nobody Sun Jun 14 07:35:29 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A66D282F06; Fri, 1 May 2026 14:51:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647098; cv=none; b=CqIHLY1iiBJ4JXG9a94NqTMPs0NLICAa5PFLDxprU9tpfs+OgP3z27ZyX3eMJdWWnAA4A8h8zAxOCon0Crdt8xs0E+mEt10SPDUId08a340KYQg2Ca4GlmP6sGLmATEOLY3tC4ISSL5F5sal565bcZP74mFVTL3w0bIdU5dzVsY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647098; c=relaxed/simple; bh=YJvX++/TOSEoCT9FDL0cK+WZPvAVTeY5+PDOETC4zak=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=G2VtSewwXPOLBhIRoFVdZfZaWcFL8wO5xL8X9s1gNSsvxb6fBPg1jL3X+DhPo95UtPfvNyYuuKL+r5qx9HZotceJ69mxKUtPa3NaDD7wZiGbI6TVlijT7QzunbYESGEqYnYqKJPKLq+ZwkjZ8CLZZQEZ34YazQ+d2ruuxC6ivsA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=drl23h8A; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="drl23h8A" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 115BAC2BCB9; Fri, 1 May 2026 14:51:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777647097; bh=YJvX++/TOSEoCT9FDL0cK+WZPvAVTeY5+PDOETC4zak=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=drl23h8AzFIDUzQKNUZx7Ths5lkGdPNeqgkErE8ZQw1NnOgSpnYJI186avfNtQDyQ NjO8kcrNtGURqSNlhyUFRcH0hocF5EeZCAPa/FOTbuPmXBUStD0+hA4xVip8ZF71Ho +oU5/eCVHBfgSX2wKRQJHLIP0TyHWgDtAlPB++tK9OPOuwz6aQ7+wn1zRiRCqacSGy mHQ5HF9UhlIUdoZguvfP6E1MUUgZLQ1h9XEk3QyRFI+2XsApZwUpPKXlYnDR1Xcal7 vEkGNSyrRu01QPJNOmmmaD68kgYd5VQ6U017jdmC+skz2z09Cc2zWw+2w/52bIiMrG M9P/ImNRHtyqw== From: Chuck Lever Date: Fri, 01 May 2026 10:51:11 -0400 Subject: [PATCH 5/6] SUNRPC: Hold cd->net for the lifetime of cache files Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260501-cache-uaf-fix-v1-5-a49928bf4817@oracle.com> References: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> In-Reply-To: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> To: Misbah Anjum N , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Yang Erkun Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Chuck Lever X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=4135; i=chuck.lever@oracle.com; h=from:subject:message-id; bh=opUXJ8QSMXMhGvSCYmr3N2cvOEFPM22XT2C7DGYtB/Y=; b=owEBbQKS/ZANAwAKATNqszNvZn+XAcsmYgBp9L3wXaAj328si78RqUKwzBaCg/yg+JQ6/k191 iglg3y8RdKJAjMEAAEKAB0WIQQosuWwEobfJDzyPv4zarMzb2Z/lwUCafS98AAKCRAzarMzb2Z/ l7jjD/992F7uxDk2Kd3QWuJNY4LJw8JBti1AIXNSB/dLGho6jo6c8BIC5TxB4hd04+eToW6fO2a cnXRk8Q79Xtz6TLg6mSSeUVhm+cDTCLdct6loyDqTnuI4J44BLSZ2nnTFQBs05hJDuX7mi4hl5o wWWdA4/ugNChSfeI4ZiVFkSD3sJAvSQnnUwRgsomqg9HoUI2F/3UdLn2rlPApwM6VY10WJdYaue WRs4vD1bZu9rL/A1Y0Qo5eA7vbLIo9riBRLvPZ84JsuTJ4rjFy9Nnd1tz+hXI6rhwsOnb8pivWh Mf3z3EqEyKfdpP/74vnxOEsr9s7WoqBOQbg914SKeF3MqGEN5OdtrGHVuwHcQRANXxpg3vRyzZl BJLmGrz9XerGLo0PN/t97T0AYwR7RdGhhu7rmZRNcNn+B6XY8ZIwQh3zizU1z0jR40sTvFu4deP evZjsl/nXOiqtk5gE5NTgB95mb/blZ2v8WFURmxzJDjKdgHY3u1g1l4lZebb9VimEVBkRf7yu4d YPo9GEqToanxfz6fqlGQgCWrjibbbyJA8qgi+27TKOswexhbadaKC7vtowiyrBhlXpTSybjtBDl P9Kj/4bZqmUtiefwjpDggchDOuok0Nq9ITwzsLjzINtXhvDN12JmvSzaFX9UPHESN0id1naxFS6 oWCVgXqRiT4gtZQ== X-Developer-Key: i=chuck.lever@oracle.com; a=openpgp; fpr=28B2E5B01286DF243CF23EFE336AB3336F667F97 From: Chuck Lever Each per-net sunrpc cache exposes three files under /proc/net/rpc//: content, channel, and flush. Their open helpers (content_open, cache_open, open_flush) take a reference on cd->owner via try_module_get() but no reference on cd->net. When the network namespace exits, cache_unregister_net() followed by cache_destroy_net() free cd->hash_table and cd synchronously without RCU deferral. Any subsequent operation on the still-open file dereferences the freed cache_detail. The fault produced by sosreport on aarch64 and ppc64le shows the typical signature: cache_check_rcu() faults reading h->flags off a garbage cache_head pointer that came from __cache_seq_start() walking a freed cd->hash_table. Commit e7fcf179b82d ("NFSD: Hold net reference for the lifetime of /proc/fs/nfs/exports fd") closed this hole only for the /proc/fs/nfs/exports file, which has its own open path; the sunrpc cache files were left exposed. Take a get_net(cd->net) in content_open(), cache_open(), and open_flush() once the open has otherwise succeeded, and a matching put_net() at the tail of each release helper. Holding the net reference for the open file lifetime prevents the namespace from exiting while a cache fd is open, which in turn prevents cache_destroy_net() from running and freeing cd from under the reader. put_net() can drop the last namespace reference, in which case __put_net() queues net_cleanup_work on netns_wq. That work runs ops_undo_list() on another CPU, which invokes sunrpc_exit_net() and frees cd via cache_destroy_net(). The release helper must not dereference cd after put_net(): cache_release(), content_release(), and release_flush() therefore capture cd->owner and cd->net into local variables before calling put_net(net) and module_put(owner). Reported-by: Misbah Anjum N Closes: https://lore.kernel.org/linux-nfs/8cf80f450085ac17164e8fa1391e9635@= linux.ibm.com/ Fixes: 1b10f0b603c0 ("SUNRPC: no need get cache ref when protected by rcu") Assisted-by: Claude:claude-opus-4-7[1m] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Tested-by: Alexandr Alexandrov --- net/sunrpc/cache.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 733bcd3daa46..be7a0c8c416e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1037,6 +1037,7 @@ static int cache_open(struct inode *inode, struct fil= e *filp, if (filp->f_mode & FMODE_WRITE) atomic_inc(&cd->writers); filp->private_data =3D rp; + get_net(cd->net); return 0; } =20 @@ -1044,6 +1045,8 @@ static int cache_release(struct inode *inode, struct = file *filp, struct cache_detail *cd) { struct cache_reader *rp =3D filp->private_data; + struct module *owner; + struct net *net; =20 if (rp) { struct cache_request *rq =3D NULL; @@ -1080,7 +1083,10 @@ static int cache_release(struct inode *inode, struct= file *filp, atomic_dec(&cd->writers); cd->last_close =3D seconds_since_boot(); } - module_put(cd->owner); + owner =3D cd->owner; + net =3D cd->net; + put_net(net); + module_put(owner); return 0; } =20 @@ -1466,14 +1472,19 @@ static int content_open(struct inode *inode, struct= file *file, =20 seq =3D file->private_data; seq->private =3D cd; + get_net(cd->net); return 0; } =20 static int content_release(struct inode *inode, struct file *file, struct cache_detail *cd) { + struct module *owner =3D cd->owner; + struct net *net =3D cd->net; int ret =3D seq_release(inode, file); - module_put(cd->owner); + + put_net(net); + module_put(owner); return ret; } =20 @@ -1482,13 +1493,18 @@ static int open_flush(struct inode *inode, struct f= ile *file, { if (!cd || !try_module_get(cd->owner)) return -EACCES; + get_net(cd->net); return nonseekable_open(inode, file); } =20 static int release_flush(struct inode *inode, struct file *file, struct cache_detail *cd) { - module_put(cd->owner); + struct module *owner =3D cd->owner; + struct net *net =3D cd->net; + + put_net(net); + module_put(owner); return 0; } =20 --=20 2.53.0 From nobody Sun Jun 14 07:35:29 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E5E993CE4A6; Fri, 1 May 2026 14:51:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647099; cv=none; b=ukec4PeRgzdglxKE62PHIo84/WmRBADamRy5aVhvoWA3BVED8o8v55c2HlG3g13v9rNgoZcS/gnzVVAZHde7+in+6XaTWpjFPzR2DJZ3q7gXr346nfeqhJjo2/waNhmBTQTWtmTN6ZOCPl+W1dlfvOxzen35/y1OMNeghfy9WsY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777647099; c=relaxed/simple; bh=2T3JGcNd+/XQP2Pn11yD19WPrggjG2IMkwq0Hu0uIzw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pqxO2Q03Ol0JtTwND5DSEBRCrtNMZU5hAf9nmp8VWI/ktSwV4gMaFwX8ixoFvGFcanzeDJTFi6TYv6/iC5rQN5AXZelC2FpScBVKG2oJ9PbM+mPlphLgt6pHVTWb9PZYP9y/gxIPQpgiaR6336CIUQLM71uSmdaMb9O4JikNw0A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lC3TP10D; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lC3TP10D" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 849C6C2BCF4; Fri, 1 May 2026 14:51:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777647098; bh=2T3JGcNd+/XQP2Pn11yD19WPrggjG2IMkwq0Hu0uIzw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=lC3TP10DjkEY6CaN5D6HSZP3yDajcwLn4qUi7PX+qELdcjtPOsMNS71o0v/+mzErh GHZKolK6eWDuv7OWhPUB2vnd/oF0LfpKIdRLtiaL7yOxCH6QrbhSMxJKFLyCIPmE3o 1TeYepHiTJ6eHoSWYUigfcdEAVeYpT8Egw0WTbOgRMXuwv5CVgzSj+muECaqu5ZOum WtmejUN9cn5PjDRUdFJ2VyVV2THahh21hcGK4wVaFFBi6U9byIN1LJXAHONJ96QgCU cA5WwlNWVBL/MT5wym+Vi+Ma8nzaMx4PeTWD1G33L9Y5ijOjai9l7/LGSdFaH9DRA7 g7fzTkQMxb23w== From: Chuck Lever Date: Fri, 01 May 2026 10:51:12 -0400 Subject: [PATCH 6/6] NFSD: Convert nfsd_export_shutdown() to sunrpc_cache_destroy_net() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260501-cache-uaf-fix-v1-6-a49928bf4817@oracle.com> References: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> In-Reply-To: <20260501-cache-uaf-fix-v1-0-a49928bf4817@oracle.com> To: Misbah Anjum N , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Yang Erkun Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Chuck Lever X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=3212; i=chuck.lever@oracle.com; h=from:subject:message-id; bh=9Lx8j3bkW1U0/I06utJXlLrhrDE5QF/icgJjUzwnHek=; b=kA0DAAoBM2qzM29mf5cByyZiAGn0vfCgtcQnorQpH1BYb4jHi1B0E8EEJ0q/5rISORjTB5fos 4kCMwQAAQoAHRYhBCiy5bASht8kPPI+/jNqszNvZn+XBQJp9L3wAAoJEDNqszNvZn+XZAgP/2nO 035u2vASCu0V2VAtBlP/zKVkuSdqutQyZuEqH5vaBGMze/u1gS6QF08SwIv/Wu2g6+J8829mQJu p7bwC7eLqaJLRQnkTzPyESgRfL75E1AAVEfCm76LaZW6EyYDpviksdecsuV3YtQeBW0H7bf+Bpx qnWEW4gOGEZuZnEm8T9j0b8eQQ3xZ+zkTCbDmmynu6NAPR4QsvHt5Q4GOlAs2j3Y54QoTV0KNaW ZLzadUWCQqSwwcSo4ahbhFwdI+Zc+a5xNtd09o3dwcVsWeePFxQVQBypf5sli4a0wJaRXohpAF7 M1kxP0lgNu+j8cSaXNVFSyd3ah1kq5nYDHWRlE47vJAi5xmQGwAX5KlpcaO28YlAbAU1Gg9uKkv HvzIbznTR8g0HgJwCt1kweqqlX6GsV+fMvX7nLqn5yTl5c86qUHIlh5bvIvPFwxdc9QMCXODcF0 08am+trgtPU7iKx+3R/2/pNBk6feNeI89LJtxXEETDeLFdqqJ1ZFGpXVkcn84sI9xyI2uOn7jVh 2NryCeDCg+USUH8PTu7++d0pE6DFWXA3vNTqsAM6ibI5AdU9llnNHUG0/X7kSs685qu4mYuzfC9 2uDPO+u2H+EMwpr9+8Sz9eJhGZh+BzjCzEmpEFmjCnKBWy0tBeyjv/EFU7ksPLvtg5vWMNtcUef 8men1 X-Developer-Key: i=chuck.lever@oracle.com; a=openpgp; fpr=28B2E5B01286DF243CF23EFE336AB3336F667F97 From: Chuck Lever The earlier conversion to the shared sunrpc cache workqueue left nfsd_export_shutdown() open-coding the unregister + drain + destroy sequence to amortize a single rcu_barrier()+flush across both caches. That micro-optimization runs only on namespace teardown and module unload, neither of which is performance-sensitive. Switch both caches to sunrpc_cache_destroy_net() so that the canonical teardown idiom is applied uniformly. A future change to the per-cache release callback that requires the cache_detail to remain valid through the drain remains correct without per-call-site auditing. With the last external caller of sunrpc_cache_drain() gone, drop the symbol export and the public declaration, and mark the function static so the compiler can inline it into sunrpc_cache_destroy_net(). Assisted-by: Claude:claude-opus-4-7[1m] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Tested-by: Alexandr Alexandrov --- fs/nfsd/export.c | 8 ++------ include/linux/sunrpc/cache.h | 1 - net/sunrpc/cache.c | 7 ++----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 3c4340e743fa..c19f8e8c4f9e 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -2250,12 +2250,8 @@ nfsd_export_shutdown(struct net *net) =20 dprintk("nfsd: shutting down export module (net: %x).\n", net->ns.inum); =20 - cache_unregister_net(nn->svc_expkey_cache, net); - cache_unregister_net(nn->svc_export_cache, net); - /* One drain covers both caches' deferred release work. */ - sunrpc_cache_drain(); - cache_destroy_net(nn->svc_expkey_cache, net); - cache_destroy_net(nn->svc_export_cache, net); + sunrpc_cache_destroy_net(nn->svc_expkey_cache, net); + sunrpc_cache_destroy_net(nn->svc_export_cache, net); svcauth_unix_purge(net); =20 dprintk("nfsd: export shutdown complete (net: %x).\n", net->ns.inum); diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 84802438a5fc..22c18eeb5a97 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -238,7 +238,6 @@ extern void cache_flush(void); extern void cache_purge(struct cache_detail *detail); #define NEVER (0x7FFFFFFF) extern void sunrpc_cache_queue_release(struct rcu_work *rwork); -extern void sunrpc_cache_drain(void); extern int cache_register_net(struct cache_detail *cd, struct net *net); extern void cache_unregister_net(struct cache_detail *cd, struct net *net); =20 diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index be7a0c8c416e..62ce334104d9 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1737,18 +1737,15 @@ void sunrpc_cache_queue_release(struct rcu_work *rw= ork) } EXPORT_SYMBOL_GPL(sunrpc_cache_queue_release); =20 -/** - * sunrpc_cache_drain - drain pending cache release work - * +/* * Wait for outstanding RCU callbacks to enqueue their release * work, then flush that work to completion. */ -void sunrpc_cache_drain(void) +static void sunrpc_cache_drain(void) { rcu_barrier(); flush_workqueue(sunrpc_cache_wq); } -EXPORT_SYMBOL_GPL(sunrpc_cache_drain); =20 /** * sunrpc_cache_destroy_net - quiesce and tear down a per-net cache --=20 2.53.0