From 536a43c0d4b3c79ab31622a7edab0c2b9dbd7ae7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 22 Jun 2020 20:01:31 +0200 Subject: [PATCH] 5.4-stable patches added patches: ext4-avoid-utf8_strncasecmp-with-unstable-name.patch ext4-fix-partial-cluster-initialization-when-splitting-extent.patch --- ...-utf8_strncasecmp-with-unstable-name.patch | 65 ++++++++++ ...initialization-when-splitting-extent.patch | 118 ++++++++++++++++++ queue-5.4/series | 2 + 3 files changed, 185 insertions(+) create mode 100644 queue-5.4/ext4-avoid-utf8_strncasecmp-with-unstable-name.patch create mode 100644 queue-5.4/ext4-fix-partial-cluster-initialization-when-splitting-extent.patch diff --git a/queue-5.4/ext4-avoid-utf8_strncasecmp-with-unstable-name.patch b/queue-5.4/ext4-avoid-utf8_strncasecmp-with-unstable-name.patch new file mode 100644 index 00000000000..e8145f18793 --- /dev/null +++ b/queue-5.4/ext4-avoid-utf8_strncasecmp-with-unstable-name.patch @@ -0,0 +1,65 @@ +From 2ce3ee931a097e9720310db3f09c01c825a4580c Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 1 Jun 2020 13:05:43 -0700 +Subject: ext4: avoid utf8_strncasecmp() with unstable name + +From: Eric Biggers + +commit 2ce3ee931a097e9720310db3f09c01c825a4580c upstream. + +If the dentry name passed to ->d_compare() fits in dentry::d_iname, then +it may be concurrently modified by a rename. This can cause undefined +behavior (possibly out-of-bounds memory accesses or crashes) in +utf8_strncasecmp(), since fs/unicode/ isn't written to handle strings +that may be concurrently modified. + +Fix this by first copying the filename to a stack buffer if needed. +This way we get a stable snapshot of the filename. + +Fixes: b886ee3e778e ("ext4: Support case-insensitive file name lookups") +Cc: # v5.2+ +Cc: Al Viro +Cc: Daniel Rosenberg +Cc: Gabriel Krisman Bertazi +Signed-off-by: Eric Biggers +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20200601200543.59417-1-ebiggers@kernel.org +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/dir.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/fs/ext4/dir.c ++++ b/fs/ext4/dir.c +@@ -677,6 +677,7 @@ static int ext4_d_compare(const struct d + struct qstr qstr = {.name = str, .len = len }; + const struct dentry *parent = READ_ONCE(dentry->d_parent); + const struct inode *inode = READ_ONCE(parent->d_inode); ++ char strbuf[DNAME_INLINE_LEN]; + + if (!inode || !IS_CASEFOLDED(inode) || + !EXT4_SB(inode->i_sb)->s_encoding) { +@@ -685,6 +686,21 @@ static int ext4_d_compare(const struct d + return memcmp(str, name->name, len); + } + ++ /* ++ * If the dentry name is stored in-line, then it may be concurrently ++ * modified by a rename. If this happens, the VFS will eventually retry ++ * the lookup, so it doesn't matter what ->d_compare() returns. ++ * However, it's unsafe to call utf8_strncasecmp() with an unstable ++ * string. Therefore, we have to copy the name into a temporary buffer. ++ */ ++ if (len <= DNAME_INLINE_LEN - 1) { ++ memcpy(strbuf, str, len); ++ strbuf[len] = 0; ++ qstr.name = strbuf; ++ /* prevent compiler from optimizing out the temporary buffer */ ++ barrier(); ++ } ++ + return ext4_ci_compare(inode, name, &qstr, false); + } + diff --git a/queue-5.4/ext4-fix-partial-cluster-initialization-when-splitting-extent.patch b/queue-5.4/ext4-fix-partial-cluster-initialization-when-splitting-extent.patch new file mode 100644 index 00000000000..901b4098966 --- /dev/null +++ b/queue-5.4/ext4-fix-partial-cluster-initialization-when-splitting-extent.patch @@ -0,0 +1,118 @@ +From cfb3c85a600c6aa25a2581b3c1c4db3460f14e46 Mon Sep 17 00:00:00 2001 +From: Jeffle Xu +Date: Fri, 22 May 2020 12:18:44 +0800 +Subject: ext4: fix partial cluster initialization when splitting extent + +From: Jeffle Xu + +commit cfb3c85a600c6aa25a2581b3c1c4db3460f14e46 upstream. + +Fix the bug when calculating the physical block number of the first +block in the split extent. + +This bug will cause xfstests shared/298 failure on ext4 with bigalloc +enabled occasionally. Ext4 error messages indicate that previously freed +blocks are being freed again, and the following fsck will fail due to +the inconsistency of block bitmap and bg descriptor. + +The following is an example case: + +1. First, Initialize a ext4 filesystem with cluster size '16K', block size +'4K', in which case, one cluster contains four blocks. + +2. Create one file (e.g., xxx.img) on this ext4 filesystem. Now the extent +tree of this file is like: + +... +36864:[0]4:220160 +36868:[0]14332:145408 +51200:[0]2:231424 +... + +3. Then execute PUNCH_HOLE fallocate on this file. The hole range is +like: + +.. +ext4_ext_remove_space: dev 254,16 ino 12 since 49506 end 49506 depth 1 +ext4_ext_remove_space: dev 254,16 ino 12 since 49544 end 49546 depth 1 +ext4_ext_remove_space: dev 254,16 ino 12 since 49605 end 49607 depth 1 +... + +4. Then the extent tree of this file after punching is like + +... +49507:[0]37:158047 +49547:[0]58:158087 +... + +5. Detailed procedure of punching hole [49544, 49546] + +5.1. The block address space: +``` +lblk ~49505 49506 49507~49543 49544~49546 49547~ + ---------+------+-------------+----------------+-------- + extent | hole | extent | hole | extent + ---------+------+-------------+----------------+-------- +pblk ~158045 158046 158047~158083 158084~158086 158087~ +``` + +5.2. The detailed layout of cluster 39521: +``` + cluster 39521 + <-------------------------------> + + hole extent + <----------------------><-------- + +lblk 49544 49545 49546 49547 + +-------+-------+-------+-------+ + | | | | | + +-------+-------+-------+-------+ +pblk 158084 1580845 158086 158087 +``` + +5.3. The ftrace output when punching hole [49544, 49546]: +- ext4_ext_remove_space (start 49544, end 49546) + - ext4_ext_rm_leaf (start 49544, end 49546, last_extent [49507(158047), 40], partial [pclu 39522 lblk 0 state 2]) + - ext4_remove_blocks (extent [49507(158047), 40], from 49544 to 49546, partial [pclu 39522 lblk 0 state 2] + - ext4_free_blocks: (block 158084 count 4) + - ext4_mballoc_free (extent 1/6753/1) + +5.4. Ext4 error message in dmesg: +EXT4-fs error (device vdb): mb_free_blocks:1457: group 1, block 158084:freeing already freed block (bit 6753); block bitmap corrupt. +EXT4-fs error (device vdb): ext4_mb_generate_buddy:747: group 1, block bitmap and bg descriptor inconsistent: 19550 vs 19551 free clusters + +In this case, the whole cluster 39521 is freed mistakenly when freeing +pblock 158084~158086 (i.e., the first three blocks of this cluster), +although pblock 158087 (the last remaining block of this cluster) has +not been freed yet. + +The root cause of this isuue is that, the pclu of the partial cluster is +calculated mistakenly in ext4_ext_remove_space(). The correct +partial_cluster.pclu (i.e., the cluster number of the first block in the +next extent, that is, lblock 49597 (pblock 158086)) should be 39521 rather +than 39522. + +Fixes: f4226d9ea400 ("ext4: fix partial cluster initialization") +Signed-off-by: Jeffle Xu +Reviewed-by: Eric Whitney +Cc: stable@kernel.org # v3.19+ +Link: https://lore.kernel.org/r/1590121124-37096-1-git-send-email-jefflexu@linux.alibaba.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/extents.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -3010,7 +3010,7 @@ again: + * in use to avoid freeing it when removing blocks. + */ + if (sbi->s_cluster_ratio > 1) { +- pblk = ext4_ext_pblock(ex) + end - ee_block + 2; ++ pblk = ext4_ext_pblock(ex) + end - ee_block + 1; + partial.pclu = EXT4_B2C(sbi, pblk); + partial.state = nofree; + } diff --git a/queue-5.4/series b/queue-5.4/series index 8e461851e70..2dfb2256e48 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -280,3 +280,5 @@ mvpp2-remove-module-bugfix.patch arm64-hw_breakpoint-don-t-invoke-overflow-handler-on.patch libata-use-per-port-sync-for-detach.patch drm-encoder_slave-fix-refcouting-error-for-modules.patch +ext4-fix-partial-cluster-initialization-when-splitting-extent.patch +ext4-avoid-utf8_strncasecmp-with-unstable-name.patch -- 2.47.3