| Age | Commit message (Collapse) | Author |
|
Shahriyar Jalayeri <[email protected]> says:
This fixes an integer overflow in the SquashFS directory-table reader
that leads to a heap out-of-bounds write, and adds a regression test.
sqfs_read_directory_table() sizes the directory table with an int
multiply (metablks_count * SQFS_METADATA_BLOCK_SIZE) that wraps for a
crafted image, under-allocating the buffer that the fill loop then
overruns. It is reached by listing or reading the image (sqfsls /
sqfsload). Patch 1 guards the allocation with __builtin_mul_overflow();
patch 2 adds a test that a crafted image is rejected.
Based on v2026.07 (fdfe2ec48d5c). A reproducer is available on request.
[trini: As part of the merge, this touches on what commit
9a9d46cb5e1a ("fs/squashfs: fix heap exhaustion during symlink resolution")
also handles, but they appear to be separate issues]
Link: https://lore.kernel.org/r/[email protected]
|
|
sqfs_read_directory_table() allocates the directory table with
malloc(metablks_count * SQFS_METADATA_BLOCK_SIZE). metablks_count is an
int and SQFS_METADATA_BLOCK_SIZE is 8192, so the multiply is evaluated in
int and wraps for metablks_count >= 2^19. metablks_count comes from the
attacker-controlled superblock (sqfs_count_metablks() grows it by one per
2-byte metadata header), so a crafted image under-allocates the buffer
while the fill loop still writes metablks_count metadata blocks into it,
a heap out-of-bounds write. It is reached by listing or reading the image
(sqfsls / sqfsload). The position list allocation on the next line has the
same unchecked-multiply shape.
Size both allocations with __builtin_mul_overflow() and reject the image
on overflow, as the disk-read buffers earlier in the same function already
do. Set the error return when either allocation fails so the caller does
not proceed with a NULL directory table.
Fixes: c51006130370 ("fs/squashfs: new filesystem")
Signed-off-by: Shahriyar Jalayeri <[email protected]>
Reviewed-by: Richard Genoud <[email protected]>
|
|
Commit 57e0bb7bf00d ("fs/squashfs: add sqfs_dir_offset() error checks")
made sqfs_search_dir() reject negative returns from sqfs_dir_offset(),
but the positive range is still unbounded. Both parts of the returned
offset come from the image: 'offset' is a 16-bit inode field used
verbatim, and the matched metadata block index may be the last one in
m_list, in which case the returned block (j + 1) is one past the end
of the directory table.
The callers use the result to index dirs->dir_table[], which
sqfs_read_directory_table() allocates as m_count metadata blocks, and
then memcpy() a directory header out of it. A crafted image can
therefore read up to 64 KiB past the end of that allocation.
Reject an inode offset that cannot address a decompressed metadata
block, and verify that the resulting directory header lies entirely
within the directory table.
The existing 'offset < 0' test is dropped: 'offset' is assigned from
get_unaligned_le16() and so is never negative, meaning the test never
fired. The new upper bound covers what it was meant to catch.
Fixes: c51006130370 ("fs/squashfs: new filesystem")
Signed-off-by: Pranav Rajendran <[email protected]>
Reviewed-by: Richard Genoud <[email protected]>
|
|
sqfs_frag_lookup() validates its fragment index only against
sblk->fragments, which is read from the image superblock and is
therefore under the control of whoever supplies the image. Every
buffer access derived from that index is then made without checking
it against the size of the buffer actually read from the device:
- the fragment index table entry at 'table_offset + block *
sizeof(u64)' can be read past the end of 'table', as 'block' is
inode_fragment_index / SQFS_MAX_ENTRIES and has no upper bound;
- the metadata block header and payload are read from
'metadata_buffer' at 'table_offset', but that buffer is sized from
start_block, which comes from the unvalidated index table entry
above. A start_block just below sblk->fragment_table_start yields a
single-block buffer while SQFS_METADATA_SIZE(header) may be up to
SQFS_METADATA_BLOCK_SIZE, so both the decompression source and the
memcpy() source can run past the end of the buffer;
- 'entries' is allocated with SQFS_METADATA_BLOCK_SIZE bytes but only
partially filled, so entries[offset] can read uninitialised heap
memory when the metadata block holds fewer than offset + 1 entries.
Compute the size of both buffers explicitly, rejecting the
multiplication overflow the way sqfs_read_directory_table() already
does, and check each access against it. Also track how much of
'entries' was populated and reject an index beyond that.
A crafted SquashFS image can trigger all three cases, either crashing
U-Boot or feeding adjacent heap contents into the fragment entry that
the following data read is based on.
Fixes: c51006130370 ("fs/squashfs: new filesystem")
Signed-off-by: Pranav Rajendran <[email protected]>
Reviewed-by: Richard Genoud <[email protected]>
|
|
Allan ELKAIM <[email protected]> says:
sqfsload fails to load a file through a symlink when the squashfs
image contains a large number of inodes (e.g. a rootfs that includes
the tzdata timezone database).
Root cause: sqfs_read_nest() resolves the symlink by calling itself
recursively without first freeing the parent directory's inode and
directory table buffers. This causes a temporary double allocation
that can exhaust the U-Boot heap. When malloc() subsequently fails
inside sqfs_read_directory_table(), the error goes undetected and
sqfs_search_dir() is called with a NULL pos_list pointer, leading to:
Error: invalid inode reference to directory table.
Failed to load '/boot/Image'
Patch 1 fixes the structural problem (temporary double allocation)
and plugs the silent NULL pointer path in sqfs_read_directory_table().
Patch 2 adds the missing return-value checks on sqfs_dir_offset() that
turn any residual lookup failure into a clean error propagation.
Patch 3 (reworked in v3 following Richard Genoud's review) fixes
pre-existing leaks of dirs->entry on the error paths of
sqfs_search_dir(), by centralizing the cleanup at the 'out' label.
All patches are independent and can be reviewed separately.
The bug was first observed on U-Boot v2024.01 and is still present
on v2026.04. The patches have been tested on a Raspberry Pi CM4
running U-Boot v2026.04 (Yocto Scarthgap 5.0.17) with a 325 MB
squashfs rootfs containing 22 517 inodes. The symlink
/boot/Image -> Image-6.6.63-v8 now resolves successfully.
This series addresses the bug reported at:
https://lists.u-boot-project.org/pipermail/u-boot/2026-May/618533.html
Link: https://lore.kernel.org/r/[email protected]
|
|
Several error paths in sqfs_search_dir() return through 'goto out'
while a directory entry obtained from sqfs_readdir_nest() is still
held, leaking dirs->entry: the inode lookup failure, the symlink
nesting limit check, every allocation/tokenization failure during
symlink resolution, and the case where readdir aborts after an
entry was already read.
Instead of freeing dirs->entry at each error site, centralize the
cleanup at the 'out' label: on error, no valid entry may be handed
back to the caller, so it can be freed unconditionally there. On
success, dirs->entry is already NULL: it is freed at the end of
each token iteration and before recursing into a symlink target,
and the root directory path never allocates it.
Explicit frees remain only where a success path needs them:
between reads in the readdir loop, at the end of each token
iteration, and before the recursive call. The now-redundant frees
on individual error paths are removed.
Suggested-by: Richard Genoud <[email protected]>
Signed-off-by: Allan ELKAIM <[email protected]>
|
|
sqfs_dir_offset() returns a negative errno on failure, but three
call sites in sqfs_search_dir() use the return value as an array
index without checking for errors first. If the lookup fails,
dirs->table is set to an invalid address, leading to undefined
behavior.
Add negative-value guards after each sqfs_dir_offset() call so
that any lookup failure propagates cleanly as an error rather
than producing incorrect results.
Note: the corresponding sqfs_find_inode() NULL checks and the
heap exhaustion fix during symlink resolution are applied in
separate patches.
Acked-by: Miquel Raynal <[email protected]>
Reviewed-by: Richard Genoud <[email protected]>
Signed-off-by: Allan ELKAIM <[email protected]>
|
|
When sqfs_read_nest() encounters a symlink it resolves it by calling
itself recursively. In the unfixed code this looks like:
// dirsp is open: inode_table + dir_table still on heap
resolved = sqfs_resolve_symlink(symlink, filename);
ret = sqfs_read_nest(resolved, ...); // recursive: allocates a new
// inode_table + dir_table pair
free(resolved);
goto out;
// out: sqfs_closedir(dirsp) <- parent tables freed HERE, too late
There is no permanent leak: the parent's tables are freed at the
out: label once the recursive call returns. However, for the entire
duration of the recursive call both the parent's inode_table +
dir_table and the child's inode_table + dir_table are live on the
heap simultaneously. On large squashfs images these tables can be
significant in size, and this temporary double allocation may exhaust
the heap budget.
A superficial workaround would be to increase CONFIG_SYS_MALLOC_LEN,
but that wastes memory on all boards and does not address the
structural problem. The correct fix is to change the freeing order:
release the parent directory's resources before recursing. This way
only one set of inode and directory tables is live at any given time,
halving the peak heap usage during symlink resolution.
When heap exhaustion does occur and malloc returns NULL for dir_table
or pos_list inside sqfs_read_directory_table(), the failure is
currently silent and cascading:
- metablks_count is not reset to -1 before the goto out, so the
function returns a positive block count alongside a NULL pointer.
- sqfs_opendir_nest() does not detect the failure (it only checks
metablks_count < 1) and calls sqfs_search_dir() with m_list=NULL.
- sqfs_dir_offset() iterates over m_list[0..n], reading from
addresses 0x0, 0x4, 0x8, ... None of those values match the
inode's start_block, so the function returns -EINVAL.
- The error propagates up as a load failure with no indication
that the root cause was heap exhaustion:
Error: invalid inode reference to directory table.
Failed to load '<symlink path>'
Two fixes:
1. In sqfs_read_directory_table(), set metablks_count = -1 whenever
malloc fails after sqfs_count_metablks() returns a positive value,
so that the caller's "metablks_count < 1" check correctly detects
the failure and avoids calling sqfs_search_dir() with a NULL
pos_list.
2. In sqfs_read_nest() and sqfs_size_nest(), call sqfs_closedir() on
the parent dirsp before the recursive call so that the parent's
inode and directory tables are freed before the child allocates
its own. Only one set of tables is then live at any given time,
halving peak heap usage during symlink resolution.
Link: https://lists.denx.de/pipermail/u-boot/2026-May/618533.html
Reviewed-by: Richard Genoud <[email protected]>
Acked-by: Miquel Raynal <[email protected]>
Signed-off-by: Allan ELKAIM <[email protected]>
|
|
It might still be a positive number due to the call to sqfs_disk_read.
This only happens when reading a file from an uncompressed squashfs.
I found this by trying to boot using the extlinux bootmethod, where
positive values are treated as errors.
Signed-off-by: Michael Zimmermann <[email protected]>
Acked-by: Richard Genoud <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
|
|
Implement spl_load_image_sqfs() in spl code.
This will be used in MMC to read a file from a squashfs partition.
Also, loosen squashfs read checks on file size by not failing when a
bigger size than the actual file size is requested. (Just read the file)
This is needed for FIT loading, because the length is ALIGNed.
Signed-off-by: Richard Genoud <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
Reviewed-by: João Marcos Costa <[email protected]>
|
|
Switch to if (CONFIG_IS_ENABLED()) instead of #if when possible and
remove unnecessary cases.
Signed-off-by: Richard Genoud <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
Reviewed-by: João Marcos Costa <[email protected]>
|
|
CONFIG_IS_ENABLED() must be used in place of IS_ENABLED() for config
options that have a _SPL_ counterpart.
Signed-off-by: Richard Genoud <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
Reviewed-by: João Marcos Costa <[email protected]>
|
|
sqfs_frag_lookup() reads a 16-bit metadata block header whose lower
15 bits encode the data size. Unlike sqfs_read_metablock() in
sqfs_inode.c, this function does not validate that the decoded size is
within SQFS_METADATA_BLOCK_SIZE (8192). A malformed SquashFS image can
set the size field to any value up to 32767, causing memcpy to write
past the 8192-byte 'entries' heap buffer.
Add the same bounds check used by sqfs_read_metablock(): reject any
metadata block header with SQFS_METADATA_SIZE(header) exceeding
SQFS_METADATA_BLOCK_SIZE.
Found by fuzzing with libFuzzer + AddressSanitizer.
Signed-off-by: Eric Kilmer <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
An integer overflow in length calculation could lead to
under-allocation and buffer overcopy.
Signed-off-by: Timo tp Preißl <[email protected]>
Reviewed-by: Tom Rini <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
Reviewed-by: João Marcos Costa <[email protected]>
|
|
Returning immediately from sqfs_read_nest is not consistent with other
error checks in this function and can lead to memory leaks. Instead use
the unwind goto used elsewhere to ensure that the memory is freed.
This issue was found by Smatch.
Signed-off-by: Andrew Goodbody <[email protected]>
Acked-by: Quentin Schulz <[email protected]>
Reviewed-by: Joao Marcos Costa <[email protected]>
|
|
* Use calloc() to allocate token_list. This avoids an illegal free if
sqfs_tokenize() fails.
* Do not iterate over token_list if it has not been allocated.
Addresses-Coverity-ID: 510453: Null pointer dereferences (FORWARD_NULL)
Signed-off-by: Heinrich Schuchardt <[email protected]>
Reviewed-by: Joao Marcos Costa <[email protected]>
Reviewed-by: Joao Marcos Costa <[email protected]>
|
|
It is confusing to have both "$(PHASE_)" and "$(XPL_)" be used in our
Makefiles as part of the macros to determine when to do something in our
Makefiles based on what phase of the build we are in. For consistency,
bring this down to a single macro and use "$(PHASE_)" only.
Signed-off-by: Tom Rini <[email protected]>
|
|
In case MAX_SYMLINK_NEST is reached while determining the size
on a symlink node, the function returns immediately.
This would not free the resources after the free_strings: label
causing a memory leak.
Set the ret value and just break out of the switch to fix this.
Signed-off-by: Andrea della Porta <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
The length of buffers used to read inode tables, directory tables, and
reading a file are calculated as: number of blocks * block size, and
such plain multiplication is prone to overflowing (thus unsafe).
Replace it by __builtin_mul_overflow, i.e. safe math.
Signed-off-by: Joao Marcos Costa <[email protected]>
|
|
A squashfs filesystem with extended attributes (xattrs) may have
inodes of type SQFS_LSYMLINK_TYPE. This might cause u-boot to fail to
handle the filesystem since it assumes a SYMLINK_TYPE and LSYMLINK_TYPE
inode are the same size. This is wrong, see:
https://github.com/plougher/squashfs-tools/blob/master/squashfs-tools/read_fs.c#L421
Using the mksquashfs '-no-xattrs' argument is probably best, but the
mksquashfs '-xattrs' argument is the default.
This patch fixes squashfs image handling by making sure parsing the
uncompressed inode_table (with sqfs_find_inode) succeeeds. The only change
needed is correctly determining the size of a SQFS_LSYMLINK_TYPE inode.
Signed-off-by: Norbert van Bolhuis <[email protected]>
|
|
Use XPL_ as the symbol to indicate an SPL build. This means that SPL_ is
no-longer set.
Signed-off-by: Simon Glass <[email protected]>
|
|
res needs to be large enough to store both strings rem and target,
plus the path separator and the terminator.
Currently the space for the path separator is not accounted, so
the heap is corrupted by one byte.
Signed-off-by: Richard Weinberger <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
The squashfs driver blindly follows symlinks, and calls sqfs_size()
recursively. So an attacker can create a crafted filesystem and with
a deep enough nesting level a stack overflow can be achieved.
Fix by limiting the nesting level to 8.
Signed-off-by: Richard Weinberger <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
The function can fail and return NULL.
Signed-off-by: Richard Weinberger <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
A carefully crafted squashfs filesystem can exhibit an extremly large
inode size and overflow the calculation in sqfs_inode_size().
As a consequence, the squashfs driver will read from wrong locations.
Fix by using __builtin_add_overflow() to detect the overflow.
Signed-off-by: Richard Weinberger <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
A carefully crafted squashfs filesystem can exhibit an inode size of 0xffffffff,
as a consequence malloc() will do a zero allocation.
Later in the function the inode size is again used for copying data.
So an attacker can overwrite memory.
Avoid the overflow by using the __builtin_add_overflow() helper.
Signed-off-by: Richard Weinberger <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
The structure is identical to the existing compressor implementations,
trivially adding lz4 decompression to sqfs_decompress.
The changes were tested using a sandbox build. An LZ4 compressed
squashfs image was bound as a host block device.
Signed-off-by: David Oberhollenzer <[email protected]>
Reviewed-by: Joao Marcos Costa <[email protected]>
|
|
This patch removes a number of struct and macro declaration that
were found through `git-grep` to be unused. Most of those are
related to compressor options and super block flags.
For reading a SquashFS image, we do not need the compressor options
or the flags. Those only encode settings used for packing the image,
mksquashfs uses them when appending data to an existing image. The
kernel implementation does not touch those, and we don't need them
either.
Signed-off-by: David Oberhollenzer <[email protected]>
|
|
Update the zstd implementation to match Linux zstd 1.5.2 from commit
2aa14b1ab2.
This was motivated by running into decompression corruption issues when
trying to uncompress files compressed with newer versions of zstd. zstd
users also claim significantly improved decompression times with newer
zstd versions which is a side benefit.
Original zstd code was copied from Linux commit 2aa14b1ab2 which is a
custom-built implementation based on zstd 1.3.1. Linux switched to an
implementation that is a copy of the upstream zstd code in Linux commit
e0c1b49f5b, this results in a large code diff. However this should make
future updates easier along with other benefits[1].
This commit is a straight mirror of the Linux zstd code, except to:
- update a few #include that do not translate cleanly
- linux/swab.h -> asm/byteorder.h
- linux/limits.h -> linux/kernel.h
- linux/module.h -> linux/compat.h
- remove assert() from debug.h so it doesn't conflict with u-boot's
assert()
- strip out the compressor code as was done in the previous u-boot zstd
- update existing zstd users to the new Linux zstd API
- change the #define for MEM_STATIC to use INLINE_KEYWORD for codesize
- add a new KConfig option that sets zstd build options to minify code
based on zstd's ZSTD_LIB_MINIFY[2].
These changes were tested by booting a zstd 1.5.2 compressed kernel inside a
FIT. And the squashfs changes by loading a file from zstd compressed squashfs
with sqfsload. buildman was used to compile test other boards and check for
binary bloat, as follows:
> $ buildman -b zstd2 --boards dh_imx6,m53menlo,mvebu_espressobin-88f3720,sandbox,sandbox64,stm32mp15_dhcom_basic,stm32mp15_dhcor_basic,turris_mox,turris_omnia -sS
> Summary of 6 commits for 9 boards (8 threads, 1 job per thread)
> 01: Merge branch '2023-01-10-platform-updates'
> arm: w+ m53menlo dh_imx6
> 02: lib: zstd: update to latest Linux zstd 1.5.2
> aarch64: (for 2/2 boards) all -3186.0 rodata +920.0 text -4106.0
> arm: (for 5/5 boards) all +1254.4 rodata +940.0 text +314.4
> sandbox: (for 2/2 boards) all -4452.0 data -16.0 rodata +640.0 text -5076.0
[1] https://github.com/torvalds/linux/commit/e0c1b49f5b674cca7b10549c53b3791d0bbc90a8
[2] https://github.com/facebook/zstd/blob/f302ad8811643c428c4e3498e28f53a0578020d3/lib/libzstd.mk#L31
Signed-off-by: Brandon Maier <[email protected]>
[trini: Set ret to -EINVAL for the error of "failed to detect
compressed" to fix warning, drop ZSTD_SRCSIZEHINT_MAX for non-Linux host
tool builds]
Signed-off-by: Tom Rini <[email protected]>
|
|
For a squashfs filesystem, the fragment table is followed by
the following tables: NFS export table, ID table, xattr table.
The export and xattr tables are both completely optional, but
the ID table is mandatory. The Linux implementation refuses to
mount the image if the ID table is missing. Tables that are no
present have their location in the super block set
to 0xFFFFFFFFFFFFFFFF.
The u-boot implementation previously assumed that it can always
rely on the export table location as an upper bound for the fragment
table, trying (and failing) to read past filesystem bounds if it
is not present.
This patch changes the driver to use the ID table instead and only
use the export table location if it lies between the two.
Signed-off-by: David Oberhollenzer <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
When compling for x86:
u-boot/fs/squashfs/sqfs.c:90: undefined reference to `__udivmoddi4'
Signed-off-by: Kasper Revsbech <[email protected]>
Tested-by: Sean Nyekjaer <[email protected]>
|
|
|
|
A crafted squashfs image could embed a huge number of empty metadata
blocks in order to make the amount of malloc()'d memory overflow and be
much smaller than expected. Because of this flaw, any random code
positioned at the right location in the squashfs image could be memcpy'd
from the squashfs structures into U-Boot code location while trying to
access the rearmost blocks, before being executed.
In order to prevent this vulnerability from being exploited in eg. a
secure boot environment, let's add a check over the amount of data
that is going to be allocated. Such a check could look like:
if (!elem_size || n > SIZE_MAX / elem_size)
return NULL;
The right way to do it would be to enhance the calloc() implementation
but this is quite an impacting change for such a small fix. Another
solution would be to add the check before the malloc call in the
squashfs implementation, but this does not look right. So for now, let's
use the kcalloc() compatibility function from Linux, which has this
check.
Fixes: c5100613037 ("fs/squashfs: new filesystem")
Reported-by: Tatsuhiko Yasumatsu <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
Tested-by: Tatsuhiko Yasumatsu <[email protected]>
|
|
Merge in v2022.07-rc5.
|
|
Following Jincheng's report, an out-of-band write leading to arbitrary
code execution is possible because on one side the squashfs logic
accepts directory names up to 65535 bytes (u16), while U-Boot fs logic
accepts directory names up to 255 bytes long.
Prevent such an exploit from happening by capping directory name sizes
to 255. Use a define for this purpose so that developers can link the
limitation to its source and eventually kill it some day by dynamically
allocating this array (if ever desired).
Link: https://lore.kernel.org/all/CALO=DHFB+yBoXxVr5KcsK0iFdg+e7ywko4-e+72kjbcS8JBfPw@mail.gmail.com
Reported-by: Jincheng Wang <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
Tested-by: Jincheng Wang <[email protected]>
|
|
Setting sblk = NULL has no effect on the caller.
We want to set *sblk = NULL if an error occurrs to avoid usage after free.
Signed-off-by: Heinrich Schuchardt <[email protected]>
|
|
Signed-off-by: Pali Rohár <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
When compling for x86:
ld.bfd: fs/squashfs/sqfs.o: in function `sqfs_read':
u-boot/fs/squashfs/sqfs.c:1443: undefined reference to `__udivmoddi4'
ld.bfd: u-boot/fs/squashfs/sqfs.c:1521: undefined reference to `__udivmoddi4'
Signed-off-by: Sean Nyekjaer <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
Reviewed-by: Pali Rohár <[email protected]>
|
|
* Don't check argument of free(). Free does this itself.
* Reduce scope of data_buffer. Remove duplicate free().
* Avoid superfluous NULL assignment.
Signed-off-by: Heinrich Schuchardt <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
Signed-off-by: Lars Weber <[email protected]>
|
|
This message comes up a lot when scanning filesystems. It suggests to the
user that there is some sort of error, but in fact there is no reason to
expect that a particular partition has a sqfs filesystem. Other
filesystems don't print this error.
Turn it into a debug message.
Signed-off-by: Simon Glass <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
In SquashFS, the contents of a directory is stored by
squashfs_directory_entry structures which contain the file's name, inode
and position within the filesystem.
The inode number is not stored directly; instead each directory has one
or more headers which set a base inode number, and files store the
offset from that to the file's inode number.
In mksquashfs, each inode is allocated a number in the same order as
they are written to the directory table; thus the offset from the
header's base inode number to the file's inode number is usually
positive.
Hardlinks are simply stored with two directory entries referencing the
same file. This means the second entry will thus have an inode number
much lower than the surrounding files. Since the header's base inode
number comes from the first entry that uses the header, this delta will
usually be negative.
Previously, U-Boot's squashfs_directory_entry.inode_offset field was
declared as an unsigned value. Thus when a negative value was found, it
would either resolve to an invalid inode number or to that of an
unrelated file.
A squashfs image to test this can be created like so:
echo hi > sqfs_test_files/001-root-file
mkdir sqfs_test_files/002-subdir
touch sqfs_test_files/002-subdir/003-file
ln sqfs_test_files/{001-root-file,002-subdir/004-link}
mksquashfs sqfs_test_files/ test.sqfs -noappend
Note that squashfs sorts the files ASCIIbetacally, so we can use the
names to control the order they appear in. The ordering is important -
the first reference to the file must have a lower inode number than the
directory in which the second reference resides, and the second
reference cannot be the first file in the directory.
Listing this sample image in U-Boot results in:
=> sqfsls virtio 2 002-subdir
0 003-file
Inode not found.
0 004-link
Signed-off-by: Campbell Suter <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
The fragmented files were not correctly read because of two issues:
- The squashfs_file_info struct has a field named 'comp', which tells if
the file's fragment is compressed or not. This field was always set to
'true' in sqfs_get_regfile_info and sqfs_get_lregfile_info. It should
actually take sqfs_frag_lookup's return value. This patch addresses
these two assignments.
- In sqfs_read, the fragments (compressed or not) were copied to the
output buffer through a for loop which was reading data at the wrong
offset. Replace these loops by equivalent calls to memcpy, with the
right parameters.
I tested this patch by comparing the MD5 checksum of a few fragmented
files with the respective md5sum output in sandbox, considering both
compressed and uncompressed fragments.
Signed-off-by: Joao Marcos Costa <[email protected]>
Tested-by: Richard Genoud <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
When reading directories the UEFI sub-system must supply file attributes
and timestamps. These fields will have to be added to struct fs_dirent.
SquashFS should not fill these fields with random data. Ensure that they
are zeroed out.
Signed-off-by: Heinrich Schuchardt <[email protected]>
Reviewed-by: Miquel Raynal <[email protected]>
|
|
Commit 401d1c4f5d2d29c4bc4beaec95402ca23eb63295 ("common: Drop
asm/global_data.h from common header") broke compilation of squashfs
filesystem when CONFIG_CMD_SQUASHFS=y is enabled.
Compilation is failing on error:
aarch64-linux-gnu-ld.bfd: u-boot/fs/squashfs/sqfs_inode.c:121: undefined reference to `le32_to_cpu'
Fixes: 401d1c4f5d2d29c4bc4beaec95402ca23eb63295 ("common: Drop asm/global_data.h from common header")
Suggested-by: Tom Rini <[email protected]>
Signed-off-by: Pali Rohár <[email protected]>
Reviewed-by: Tom Rini <[email protected]>
|
|
sqfs_opendir() called in sqfs_size(), sqfs_read(), sqfs_exists() may fail
leading to sqfs_closedir(NULL) being called. Do not dereference NULL.
Signed-off-by: Heinrich Schuchardt <[email protected]>
|
|
SquashFS supports sprase blocks in files - that is, if a given block is
composed only of zeros, it's not written to the output file to save
space and it's on-disk length field is set to zero to indicate that.
Previously the squashfs driver did not recognise that, and would attempt
to read and decompress a zero-sized block, which obviously failed.
The following command may be used to create a file for testing:
cat <(dd if=/dev/urandom of=/dev/stdout bs=1M count=1) \
<(dd if=/dev/zero of=/dev/stdout bs=1M count=1) \
<(dd if=/dev/urandom of=/dev/stdout bs=1k count=200) >test_file
Signed-off-by: Campbell Suter <[email protected]>
|
|
This will prevent a double free error if sqfs_close() is called twice.
Signed-off-by: Richard Genoud <[email protected]>
|
|
This permits to find a file and use the distro_bootcmd
Reviewed-by: Joao Marcos Costa <[email protected]>
Signed-off-by: Richard Genoud <[email protected]>
|
|
offset is the offset in the file read, not the offset in the destination
buffer.
If the offset is not null, this will lead to a memory corruption.
So, for now, we are returning an error if the offset is used.
Signed-off-by: Richard Genoud <[email protected]>
|