Commit bfca5fb4e97c ("SUNRPC: Fix RPC client cleaned up the freed pipefs dentries") added a clnt->pipefs_sb field and a consistency check in rpc_clnt_remove_pipedir() so that pipedir cleanup is skipped when the current superblock does not match the one recorded in the client. However, __rpc_clnt_handle_event() never updates clnt->pipefs_sb when it creates or removes pipedirs in response to RPC_PIPEFS_MOUNT and RPC_PIPEFS_UMOUNT notifications. This causes a problem for RPC clients that are registered before rpc_pipefs is mounted (e.g., before rpc_pipefs is mounted during boot, or after it has been unmounted). Such clients have clnt->pipefs_sb set to NULL at registration time because rpc_get_sb_net() returns NULL. When rpc_pipefs is mounted later, __rpc_clnt_handle_event(MOUNT) creates the pipedir but leaves clnt->pipefs_sb as NULL. When the client is later destroyed, rpc_clnt_remove_pipedir() sees that the current superblock does not match clnt->pipefs_sb and skips cleanup, leaving orphaned dentries whose RPC_I(inode)->private pointers reference freed rpc_clnt memory. Any subsequent access to these orphaned info files triggers a use-after-free [1]. Fix this by setting clnt->pipefs_sb in __rpc_clnt_handle_event() on MOUNT and clearing it on UMOUNT, mirroring what rpc_setup_pipedir() already does at client registration time. [1] BUG: KASAN: slab-use-after-free in rpc_info_open (net/sunrpc/rpc_pipe.c:426) Read of size 4 at addr ffff88802ebe0800 by task cat/5079 Call Trace: ... rpc_info_open (net/sunrpc/rpc_pipe.c:426) do_dentry_open (fs/open.c:947) vfs_open (fs/open.c:1052) path_openat (fs/namei.c:4700 fs/namei.c:4863) do_file_open (fs/namei.c:4892) do_sys_openat2 (fs/open.c:1368) __x64_sys_openat (fs/open.c:1385) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) Allocated by task 5048: ... rpc_new_client (net/sunrpc/clnt.c:377) __rpc_clone_client (net/sunrpc/clnt.c:645) rpc_clone_client_set_auth (net/sunrpc/clnt.c:706) nfs_init_server_rpcclient (fs/nfs/client.c:640) nfs_clone_server (fs/nfs/client.c:1247) nfs4_clone_server (fs/nfs/nfs4proc.c:10683) nfs_do_submount (fs/nfs/namespace.c:288) ... Freed by task 24: ... kfree (mm/slub.c:6692) rpc_free_client_work (net/sunrpc/clnt.c:987) process_scheduled_works (kernel/workqueue.c:3405) worker_thread (kernel/workqueue.c:3486) ... Fixes: bfca5fb4e97c ("SUNRPC: Fix RPC client cleaned up the freed pipefs dentries") Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Shigeru Yoshida --- net/sunrpc/clnt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index efa26899bc7d..55617d263d2f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -179,11 +179,17 @@ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event) static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event, struct super_block *sb) { + int err; + switch (event) { case RPC_PIPEFS_MOUNT: - return rpc_setup_pipedir_sb(sb, clnt); + err = rpc_setup_pipedir_sb(sb, clnt); + if (!err) + clnt->pipefs_sb = sb; + return err; case RPC_PIPEFS_UMOUNT: __rpc_clnt_remove_pipedir(clnt); + clnt->pipefs_sb = NULL; break; default: printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event); -- 2.55.0