diff --git a/patches.kernel.org/6.3.3-228-ext4-fix-data-races-when-using-cached-status-ex.patch b/patches.kernel.org/6.3.3-228-ext4-fix-data-races-when-using-cached-status-ex.patch new file mode 100644 index 0000000..29e35bd --- /dev/null +++ b/patches.kernel.org/6.3.3-228-ext4-fix-data-races-when-using-cached-status-ex.patch @@ -0,0 +1,87 @@ +From: Jan Kara +Date: Thu, 4 May 2023 14:55:24 +0200 +Subject: [PATCH] ext4: fix data races when using cached status extents +References: bsc#1012628 +Patch-mainline: 6.3.3 +Git-commit: 492888df0c7b42fc0843631168b0021bc4caee84 + +commit 492888df0c7b42fc0843631168b0021bc4caee84 upstream. + +When using cached extent stored in extent status tree in tree->cache_es +another process holding ei->i_es_lock for reading can be racing with us +setting new value of tree->cache_es. If the compiler would decide to +refetch tree->cache_es at an unfortunate moment, it could result in a +bogus in_range() check. Fix the possible race by using READ_ONCE() when +using tree->cache_es only under ei->i_es_lock for reading. + +Cc: stable@kernel.org +Reported-by: syzbot+4a03518df1e31b537066@syzkaller.appspotmail.com +Link: https://lore.kernel.org/all/000000000000d3b33905fa0fd4a6@google.com +Suggested-by: Dmitry Vyukov +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20230504125524.10802-1-jack@suse.cz +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Jiri Slaby +--- + fs/ext4/extents_status.c | 30 +++++++++++++----------------- + 1 file changed, 13 insertions(+), 17 deletions(-) + +diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c +index 7bc22103..595abb9e 100644 +--- a/fs/ext4/extents_status.c ++++ b/fs/ext4/extents_status.c +@@ -267,14 +267,12 @@ static void __es_find_extent_range(struct inode *inode, + + /* see if the extent has been cached */ + es->es_lblk = es->es_len = es->es_pblk = 0; +- if (tree->cache_es) { +- es1 = tree->cache_es; +- if (in_range(lblk, es1->es_lblk, es1->es_len)) { +- es_debug("%u cached by [%u/%u) %llu %x\n", +- lblk, es1->es_lblk, es1->es_len, +- ext4_es_pblock(es1), ext4_es_status(es1)); +- goto out; +- } ++ es1 = READ_ONCE(tree->cache_es); ++ if (es1 && in_range(lblk, es1->es_lblk, es1->es_len)) { ++ es_debug("%u cached by [%u/%u) %llu %x\n", ++ lblk, es1->es_lblk, es1->es_len, ++ ext4_es_pblock(es1), ext4_es_status(es1)); ++ goto out; + } + + es1 = __es_tree_search(&tree->root, lblk); +@@ -293,7 +291,7 @@ static void __es_find_extent_range(struct inode *inode, + } + + if (es1 && matching_fn(es1)) { +- tree->cache_es = es1; ++ WRITE_ONCE(tree->cache_es, es1); + es->es_lblk = es1->es_lblk; + es->es_len = es1->es_len; + es->es_pblk = es1->es_pblk; +@@ -931,14 +929,12 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, + + /* find extent in cache firstly */ + es->es_lblk = es->es_len = es->es_pblk = 0; +- if (tree->cache_es) { +- es1 = tree->cache_es; +- if (in_range(lblk, es1->es_lblk, es1->es_len)) { +- es_debug("%u cached by [%u/%u)\n", +- lblk, es1->es_lblk, es1->es_len); +- found = 1; +- goto out; +- } ++ es1 = READ_ONCE(tree->cache_es); ++ if (es1 && in_range(lblk, es1->es_lblk, es1->es_len)) { ++ es_debug("%u cached by [%u/%u)\n", ++ lblk, es1->es_lblk, es1->es_len); ++ found = 1; ++ goto out; + } + + node = tree->root.rb_node; +-- +2.35.3 + diff --git a/series.conf b/series.conf index 5b11fdf..6b0e505 100644 --- a/series.conf +++ b/series.conf @@ -961,6 +961,7 @@ patches.kernel.org/6.3.3-225-locking-rwsem-Add-__always_inline-annotation-to.patch patches.kernel.org/6.3.3-226-ext4-fix-WARNING-in-mb_find_extent.patch patches.kernel.org/6.3.3-227-ext4-avoid-a-potential-slab-out-of-bounds-in-ex.patch + patches.kernel.org/6.3.3-228-ext4-fix-data-races-when-using-cached-status-ex.patch ######################################################## # Build fixes that apply to the vanilla kernel too.