From: Shiji Yang Date: Thu, 8 Jan 2026 13:10:56 +0000 (+0800) Subject: tools/squashfs4: fix rare data corruption issue X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d93429888c847b0604bd504640c6f3c4dda3fc3d;p=thirdparty%2Fopenwrt.git tools/squashfs4: fix rare data corruption issue There is a chance that the squashfs4 tool may create a broken image under certain conditions. Backport the fix from upstream to address this issue. Report: https://forum.openwrt.org/t/bug-squashfs4-tools-4-7-4-create-corrupted-image/244894 Fixes: 64432358e098 ("tools/squashfs4: update to 4.7.3") Reported-by: Oleg S Signed-off-by: Shiji Yang Link: https://github.com/openwrt/openwrt/pull/21458 Signed-off-by: Robert Marko --- diff --git a/tools/squashfs4/Makefile b/tools/squashfs4/Makefile index 6b887353b6e..43891a1d5d9 100644 --- a/tools/squashfs4/Makefile +++ b/tools/squashfs4/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=squashfs4 PKG_CPE_ID:=cpe:/a:phillip_lougher:squashfs PKG_VERSION:=4.7.4 -PKG_RELEASE=1 +PKG_RELEASE=2 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/plougher/squashfs-tools diff --git a/tools/squashfs4/patches/0001-mksquashfs-don-t-create-duplicate-virtual-real-disk-.patch b/tools/squashfs4/patches/0001-mksquashfs-don-t-create-duplicate-virtual-real-disk-.patch new file mode 100644 index 00000000000..5f2d7ad7bd1 --- /dev/null +++ b/tools/squashfs4/patches/0001-mksquashfs-don-t-create-duplicate-virtual-real-disk-.patch @@ -0,0 +1,101 @@ +From 767d44ceff8fc8e1e7a47a0bcafdcc40eaeb6503 Mon Sep 17 00:00:00 2001 +From: Phillip Lougher +Date: Thu, 8 Jan 2026 01:20:40 +0000 +Subject: [PATCH] mksquashfs: don't create duplicate virtual -> real disk + mappings + +This bug is caused by commit 472588dc40292fa3d047369f1e758016a6b26e70, +but it is exposed by commit 078529915caab11e85299aac1304671151d507a3. + +The first commit adds a virtual -> real disk mapping in cases where a +multi-block file contains all sparse blocks. In this case no data +block has been written for this file, and it may mean no virtual -> real +disk mapping will exist otherwise. + +However, a side effect of this is two duplicate virtual -> real disk +mappings may be created, with different values. + +Now previously before commit 078529915caab11e85299aac1304671151d507a3, +Mksquashfs waited for all outstanding data blocks to be processed by the +orderer thread before creating the metadata. At this point all the +duplicate virtual -> real disk mappings will exist, and the lookup +routine will return the last one created - which happens to be the +correct one. + +After commit 078529915caab11e85299aac1304671151d507a3, Mksquashfs no +longer waits for all outstanding data blocks to be processed by the +orderer thread, which means when the lookup takes place in metadata +creation, there may exist only the first wrong duplicate, which will be +returned. Obviously there may exist both duplicate values in which case +the correct one will be returned. In other words this is a race +condition, and it is highly dependent on hardware and input data +whether it triggers. + +The fix is to increment the virtual disk position after creating a +mapping when a multi-block file contains all sparse blocks. This +obviously prevents duplicate mappings from being created. + +Fixes https://github.com/plougher/squashfs-tools/issues/339 + +Signed-off-by: Phillip Lougher +--- + squashfs-tools/mksquashfs.c | 12 +++++++++--- + squashfs-tools/virt_disk_pos.h | 9 +++++++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +--- a/squashfs-tools/mksquashfs.c ++++ b/squashfs-tools/mksquashfs.c +@@ -2923,8 +2923,10 @@ static struct file_info *write_file_proc + fragment_buffer ? fragment_buffer->checksum : 0, FALSE, + TRUE); + +- if(!is_vpos_marked()) ++ if(!is_vpos_marked()) { + send_orderer_create_map(get_marked_vpos()); ++ inc_vpos(); ++ } + + gen_cache_block_put(fragment_buffer); + file_count ++; +@@ -3027,8 +3029,10 @@ static struct file_info *write_file_bloc + if(buffer_list[block]) + put_write_buffer_hash(buffer_list[block]); + +- if(!is_vpos_marked()) ++ if(!is_vpos_marked()) { + send_orderer_create_map(get_marked_vpos()); ++ inc_vpos(); ++ } + } else { + for(block = thresh; block < blocks; block ++) + gen_cache_block_put(buffer_list[block]); +@@ -3140,8 +3144,10 @@ static struct file_info *write_file_bloc + block_list, get_marked_vpos(), fragment, 0, fragment_buffer ? + fragment_buffer->checksum : 0, FALSE, TRUE); + +- if(!is_vpos_marked()) ++ if(!is_vpos_marked()) { + send_orderer_create_map(get_marked_vpos()); ++ inc_vpos(); ++ } + + gen_cache_block_put(fragment_buffer); + file_count ++; +--- a/squashfs-tools/virt_disk_pos.h ++++ b/squashfs-tools/virt_disk_pos.h +@@ -96,6 +96,15 @@ static inline long long get_and_inc_vpos + } + + ++static inline void inc_vpos() ++{ ++ if(marked_vpos == 0) ++ BAD_ERROR("BUG: Saved write position is empty!\n"); ++ ++ vpos ++; ++} ++ ++ + static inline int reset_vpos(void) + { + if(marked_vpos == 0)