tools/squashfs4: fix rare data corruption issue
Some checks failed
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled

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: 64432358e0 ("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>
(cherry picked from commit d93429888c)
This commit is contained in:
Shiji Yang 2026-01-08 21:10:56 +08:00 committed by Robert Marko
parent 99a46b745c
commit d925dd4887
2 changed files with 102 additions and 1 deletions

View 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

View file

@ -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)