sunrpc: fix use-after-free in __rpc_clnt_handle_event and __rpc_clnt_remove_pipedir
Subsystems (4)
PATCH 1/1 sunrpc: fix use-after-free in __rpc_clnt_handle_event and __rpc_clnt_remove_pipedir
In reply to a message not in the archiveFrom: Luxiao Xu <[email protected]>
Normal client creation goes through rpc_setup_pipedir(), which records clnt->pipefs_sb, but the mount-event path in __rpc_clnt_handle_event() calls rpc_setup_pipedir_sb() directly and never refreshes that field. The umount path also removes the directory without clearing clnt->pipefs_sb.
After a late pipefs mount or any remount, rpc_clnt_remove_pipedir() compares the current superblock against a stale pipefs_sb pointer and skips cleanup, leaving pipefs dentries whose inode private data still points at a freed rpc_clnt, leading to a potential use-after-free during subsequent rpc_info_open() or rpc_show_info() calls.
Fix this by properly updating clnt->pipefs_sb upon mount events and clearing it during unmount or failure paths.
--- net/sunrpc/clnt.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
net/sunrpc/clnt.c +17 -5
@@ -96,7 +96,10 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)static void __rpc_clnt_remove_pipedir (struct rpc_clnt *clnt) { -rpc_remove_client_dir (clnt); +if (clnt->pipefs_sb) { +rpc_remove_client_dir (clnt); + clnt->pipefs_sb =NULL ; + } }static void rpc_clnt_remove_pipedir (struct rpc_clnt *clnt)
@@ -177,19 +180,28 @@ 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) +struct super_block *sb) { +int err =0 ; +switch (event) {case RPC_PIPEFS_MOUNT : -return rpc_setup_pipedir_sb (sb, clnt); + clnt->pipefs_sb = sb; + err =rpc_setup_pipedir_sb (sb, clnt); +if (err) + clnt->pipefs_sb =NULL ; +break ;case RPC_PIPEFS_UMOUNT : -__rpc_clnt_remove_pipedir (clnt); +if (clnt->pipefs_sb == sb) { +__rpc_clnt_remove_pipedir (clnt); + clnt->pipefs_sb =NULL ; + }break ;default :printk (KERN_ERR "%s: unknown event: %ld\n" , __func__, event);return -ENOTSUPP ; } -return 0 ; +return err; } static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
Signature · 1 line
2.43.0