From d06e6eee465ebbb73228ed948918312d63aa6e6e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Jul 2024 15:29:25 +0200 Subject: [PATCH] 4.19-stable patches added patches: nilfs2-fix-kernel-bug-on-rename-operation-of-broken-directory.patch sunrpc-fix-rpc-client-cleaned-up-the-freed-pipefs-dentries.patch --- ...rename-operation-of-broken-directory.patch | 78 ++++++++++++ queue-4.19/series | 2 + ...cleaned-up-the-freed-pipefs-dentries.patch | 115 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 queue-4.19/nilfs2-fix-kernel-bug-on-rename-operation-of-broken-directory.patch create mode 100644 queue-4.19/sunrpc-fix-rpc-client-cleaned-up-the-freed-pipefs-dentries.patch diff --git a/queue-4.19/nilfs2-fix-kernel-bug-on-rename-operation-of-broken-directory.patch b/queue-4.19/nilfs2-fix-kernel-bug-on-rename-operation-of-broken-directory.patch new file mode 100644 index 00000000000..ed46a3e48d8 --- /dev/null +++ b/queue-4.19/nilfs2-fix-kernel-bug-on-rename-operation-of-broken-directory.patch @@ -0,0 +1,78 @@ +From a9e1ddc09ca55746079cc479aa3eb6411f0d99d4 Mon Sep 17 00:00:00 2001 +From: Ryusuke Konishi +Date: Sat, 29 Jun 2024 01:51:07 +0900 +Subject: nilfs2: fix kernel bug on rename operation of broken directory + +From: Ryusuke Konishi + +commit a9e1ddc09ca55746079cc479aa3eb6411f0d99d4 upstream. + +Syzbot reported that in rename directory operation on broken directory on +nilfs2, __block_write_begin_int() called to prepare block write may fail +BUG_ON check for access exceeding the folio/page size. + +This is because nilfs_dotdot(), which gets parent directory reference +entry ("..") of the directory to be moved or renamed, does not check +consistency enough, and may return location exceeding folio/page size for +broken directories. + +Fix this issue by checking required directory entries ("." and "..") in +the first chunk of the directory in nilfs_dotdot(). + +Link: https://lkml.kernel.org/r/20240628165107.9006-1-konishi.ryusuke@gmail.com +Signed-off-by: Ryusuke Konishi +Reported-by: syzbot+d3abed1ad3d367fa2627@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d3abed1ad3d367fa2627 +Fixes: 2ba466d74ed7 ("nilfs2: directory entry operations") +Tested-by: Ryusuke Konishi +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + fs/nilfs2/dir.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +--- a/fs/nilfs2/dir.c ++++ b/fs/nilfs2/dir.c +@@ -396,11 +396,39 @@ found: + + struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct page **p) + { +- struct nilfs_dir_entry *de = nilfs_get_page(dir, 0, p); ++ struct page *page; ++ struct nilfs_dir_entry *de, *next_de; ++ size_t limit; ++ char *msg; + ++ de = nilfs_get_page(dir, 0, &page); + if (IS_ERR(de)) + return NULL; +- return nilfs_next_entry(de); ++ ++ limit = nilfs_last_byte(dir, 0); /* is a multiple of chunk size */ ++ if (unlikely(!limit || le64_to_cpu(de->inode) != dir->i_ino || ++ !nilfs_match(1, ".", de))) { ++ msg = "missing '.'"; ++ goto fail; ++ } ++ ++ next_de = nilfs_next_entry(de); ++ /* ++ * If "next_de" has not reached the end of the chunk, there is ++ * at least one more record. Check whether it matches "..". ++ */ ++ if (unlikely((char *)next_de == (char *)de + nilfs_chunk_size(dir) || ++ !nilfs_match(2, "..", next_de))) { ++ msg = "missing '..'"; ++ goto fail; ++ } ++ *p = page; ++ return next_de; ++ ++fail: ++ nilfs_error(dir->i_sb, "directory #%lu %s", dir->i_ino, msg); ++ nilfs_put_page(page); ++ return NULL; + } + + ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr) diff --git a/queue-4.19/series b/queue-4.19/series index 42f19315689..fc32ea60a74 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -61,3 +61,5 @@ tcp-refactor-tcp_retransmit_timer.patch net-tcp-fix-unexcepted-socket-die-when-snd_wnd-is-0.patch tcp-use-signed-arithmetic-in-tcp_rtx_probe0_timed_out.patch tcp-avoid-too-many-retransmit-packets.patch +sunrpc-fix-rpc-client-cleaned-up-the-freed-pipefs-dentries.patch +nilfs2-fix-kernel-bug-on-rename-operation-of-broken-directory.patch diff --git a/queue-4.19/sunrpc-fix-rpc-client-cleaned-up-the-freed-pipefs-dentries.patch b/queue-4.19/sunrpc-fix-rpc-client-cleaned-up-the-freed-pipefs-dentries.patch new file mode 100644 index 00000000000..e1c5a6dfbfe --- /dev/null +++ b/queue-4.19/sunrpc-fix-rpc-client-cleaned-up-the-freed-pipefs-dentries.patch @@ -0,0 +1,115 @@ +From bfca5fb4e97c46503ddfc582335917b0cc228264 Mon Sep 17 00:00:00 2001 +From: felix +Date: Mon, 23 Oct 2023 09:40:19 +0800 +Subject: SUNRPC: Fix RPC client cleaned up the freed pipefs dentries + +From: felix + +commit bfca5fb4e97c46503ddfc582335917b0cc228264 upstream. + +RPC client pipefs dentries cleanup is in separated rpc_remove_pipedir() +workqueue,which takes care about pipefs superblock locking. +In some special scenarios, when kernel frees the pipefs sb of the +current client and immediately alloctes a new pipefs sb, +rpc_remove_pipedir function would misjudge the existence of pipefs +sb which is not the one it used to hold. As a result, +the rpc_remove_pipedir would clean the released freed pipefs dentries. + +To fix this issue, rpc_remove_pipedir should check whether the +current pipefs sb is consistent with the original pipefs sb. + +This error can be catched by KASAN: +========================================================= +[ 250.497700] BUG: KASAN: slab-use-after-free in dget_parent+0x195/0x200 +[ 250.498315] Read of size 4 at addr ffff88800a2ab804 by task kworker/0:18/106503 +[ 250.500549] Workqueue: events rpc_free_client_work +[ 250.501001] Call Trace: +[ 250.502880] kasan_report+0xb6/0xf0 +[ 250.503209] ? dget_parent+0x195/0x200 +[ 250.503561] dget_parent+0x195/0x200 +[ 250.503897] ? __pfx_rpc_clntdir_depopulate+0x10/0x10 +[ 250.504384] rpc_rmdir_depopulate+0x1b/0x90 +[ 250.504781] rpc_remove_client_dir+0xf5/0x150 +[ 250.505195] rpc_free_client_work+0xe4/0x230 +[ 250.505598] process_one_work+0x8ee/0x13b0 +... +[ 22.039056] Allocated by task 244: +[ 22.039390] kasan_save_stack+0x22/0x50 +[ 22.039758] kasan_set_track+0x25/0x30 +[ 22.040109] __kasan_slab_alloc+0x59/0x70 +[ 22.040487] kmem_cache_alloc_lru+0xf0/0x240 +[ 22.040889] __d_alloc+0x31/0x8e0 +[ 22.041207] d_alloc+0x44/0x1f0 +[ 22.041514] __rpc_lookup_create_exclusive+0x11c/0x140 +[ 22.041987] rpc_mkdir_populate.constprop.0+0x5f/0x110 +[ 22.042459] rpc_create_client_dir+0x34/0x150 +[ 22.042874] rpc_setup_pipedir_sb+0x102/0x1c0 +[ 22.043284] rpc_client_register+0x136/0x4e0 +[ 22.043689] rpc_new_client+0x911/0x1020 +[ 22.044057] rpc_create_xprt+0xcb/0x370 +[ 22.044417] rpc_create+0x36b/0x6c0 +... +[ 22.049524] Freed by task 0: +[ 22.049803] kasan_save_stack+0x22/0x50 +[ 22.050165] kasan_set_track+0x25/0x30 +[ 22.050520] kasan_save_free_info+0x2b/0x50 +[ 22.050921] __kasan_slab_free+0x10e/0x1a0 +[ 22.051306] kmem_cache_free+0xa5/0x390 +[ 22.051667] rcu_core+0x62c/0x1930 +[ 22.051995] __do_softirq+0x165/0x52a +[ 22.052347] +[ 22.052503] Last potentially related work creation: +[ 22.052952] kasan_save_stack+0x22/0x50 +[ 22.053313] __kasan_record_aux_stack+0x8e/0xa0 +[ 22.053739] __call_rcu_common.constprop.0+0x6b/0x8b0 +[ 22.054209] dentry_free+0xb2/0x140 +[ 22.054540] __dentry_kill+0x3be/0x540 +[ 22.054900] shrink_dentry_list+0x199/0x510 +[ 22.055293] shrink_dcache_parent+0x190/0x240 +[ 22.055703] do_one_tree+0x11/0x40 +[ 22.056028] shrink_dcache_for_umount+0x61/0x140 +[ 22.056461] generic_shutdown_super+0x70/0x590 +[ 22.056879] kill_anon_super+0x3a/0x60 +[ 22.057234] rpc_kill_sb+0x121/0x200 + +Fixes: 0157d021d23a ("SUNRPC: handle RPC client pipefs dentries by network namespace aware routines") +Signed-off-by: felix +Signed-off-by: Trond Myklebust +Signed-off-by: Hagar Hemdan +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/sunrpc/clnt.h | 1 + + net/sunrpc/clnt.c | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/include/linux/sunrpc/clnt.h ++++ b/include/linux/sunrpc/clnt.h +@@ -70,6 +70,7 @@ struct rpc_clnt { + struct dentry *cl_debugfs; /* debugfs directory */ + #endif + struct rpc_xprt_iter cl_xpi; ++ struct super_block *pipefs_sb; + }; + + /* +--- a/net/sunrpc/clnt.c ++++ b/net/sunrpc/clnt.c +@@ -112,7 +112,8 @@ static void rpc_clnt_remove_pipedir(stru + + pipefs_sb = rpc_get_sb_net(net); + if (pipefs_sb) { +- __rpc_clnt_remove_pipedir(clnt); ++ if (pipefs_sb == clnt->pipefs_sb) ++ __rpc_clnt_remove_pipedir(clnt); + rpc_put_sb_net(net); + } + } +@@ -152,6 +153,8 @@ rpc_setup_pipedir(struct super_block *pi + { + struct dentry *dentry; + ++ clnt->pipefs_sb = pipefs_sb; ++ + if (clnt->cl_program->pipe_dir_name != NULL) { + dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt); + if (IS_ERR(dentry)) -- 2.47.3