]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
tools/squashfs4: fix rare data corruption issue 21458/head
authorShiji Yang <yangshiji66@outlook.com>
Thu, 8 Jan 2026 13:10:56 +0000 (21:10 +0800)
committerRobert Marko <robimarko@gmail.com>
Fri, 9 Jan 2026 12:50:38 +0000 (13:50 +0100)
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 <remittor@gmail.com>
Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/21458
Signed-off-by: Robert Marko <robimarko@gmail.com>
tools/squashfs4/Makefile
tools/squashfs4/patches/0001-mksquashfs-don-t-create-duplicate-virtual-real-disk-.patch [new file with mode: 0644]

index 6b887353b6e9c6e8448fc71d1f07536554f1dd11..43891a1d5d9f9b6723ff2f22c592c437edea5a01 100644 (file)
@@ -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 (file)
index 0000000..5f2d7ad
--- /dev/null
@@ -0,0 +1,101 @@
+From 767d44ceff8fc8e1e7a47a0bcafdcc40eaeb6503 Mon Sep 17 00:00:00 2001
+From: Phillip Lougher <phillip@squashfs.org.uk>
+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 <phillip@squashfs.org.uk>
+---
+ 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)