While zalloc() takes a size_t type, adding 1 to the le32 variable
will overflow.
A carefully crafted ext4 filesystem can exhibit an inode size of 0xffffffff
and as consequence zalloc() 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 <richard@nod.at>
Evaluate the filesystem incompat and ro_compat bit fields to judge
whether the filesystem can be read or written.
For the read side only a scary warning is shown so far.
I'd love to abort mounting too, but I fear this will break some setups
where the driver works by chance.
Signed-off-by: Richard Weinberger <richard@nod.at>
As part of bringing the master branch back in to next, we need to allow
for all of these changes to exist here.
Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay
Ethernet"' I failed to notice that b4 noticed it was based on next and
so took that as the base commit and merged that part of next to master.
This reverts commit c8ffd1356d, reversing
changes made to 2ee6f3a5f7.
Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
U-Boot only knows absolute file paths. It is inconsistent to require that
saving to an ext4 file system should use a leading '/' while reading does
not. Remove the superfluous check.
Reported-by: Patrice Chotard <patrice.chotard@foss.st.com>
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Tested-by: Patrice Chotard <patrice.chotard@foss.st.com>
While fat_exists() reports directories and files as existing
ext4fs_exists() only recognizes files. This lead to errors
when using systemd-boot with an ext4 file-system.
Change ext4fs_exists() to find any type of inode:
files, directories, symbolic links.
Fixes: a1596438a6 ("ext4fs ls load support")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
This check breaks small partitions (under 1024 blocks) because part_length
is in units of part.blksz and not bytes. Given the purpose of this
function, we really want to make sure the partition is SUPERBLOCK_START +
SUPERBLOCK_SIZE (2048) bytes so we can call ext4_read_superblock without
error.
The obvious solution is to convert callers from things like
ext4fs_mount(part_info.size)
to
ext4fs_mount(part_info.size * part_info.blksz);
However, I'm not really a fan of the bloat that would cause, especially
since the error is now suppressed. I think the best course of action here
is to just revert the patch.
This reverts commit 9905cae65e.
Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
No need to mount a too small partition to handle a EXT4 file system.
This patch add a test on partition size before to read the
SUPERBLOCK_SIZE buffer and avoid error latter in fs_devread() function.
Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
The 'depth_dirname', 'ptr', 'parent_inode' and 'first_inode' pointers
may be null. Thus, it is necessary to check them before using free() to
avoid free(NULL) cases.
Fixes: 934b14f2bb ("ext4: free allocations by parse_path()")
Signed-off-by: Mikhail Ilin <ilin.mikhail.ol@gmail.com>
When looking for a filesystem on a partition we should do so quietly. At
present if the filesystem is very small (e.g. 512 bytes) we get a host of
messages.
Update these to only show when debugging.
Signed-off-by: Simon Glass <sjg@chromium.org>
Implementation in linux/crc16.h provides standard CRC-16 algorithm with
polynomial x^16 + x^15 + x^2 + 1. Use it and remove duplicate ext4 CRC-16
specific code.
Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Stefan Roese <sr@denx.de>
This patch checks for 0 in several ext4 headers and gracefully
fails instead of raising a divide-by-0 exception.
Signed-off-by: Paul Emge <paulemge@forallsecure.com>
The block count entry in the EXT4 filesystem disk structures uses
standard 512-bytes units for most of the typical files. The only
exception are HUGE files, which use the filesystem block size, but those
are not supported by uboot's EXT4 implementation anyway. This patch fixes
the EXT4 code to use proper unit count for inode block count. This fixes
errors reported by fsck.ext4 on disks with non-standard (i.e. 4KiB, in
case of new flash drives) PHYSICAL block size after using 'ext4write'
uboot's command.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Lukasz Majewski <lukma@denx.de>
Ext4 allows for arbitrarily sized block group descriptors when 64-bit
addressing is enabled, which was previously not properly supported. This
patch dynamically allocates a chunk of memory of the correct size.
Signed-off-by: Benjamin Lim <jarsp.ctf@gmail.com>
Hi,
when I try to load a sparse file via ext4load, I am getting the error message
'invalid extent'
After a deeper look in the code, it seems to be an issue in the function ext4fs_get_extent_block in fs/ext4/ext4_common.c:
The file starts with 1k of zeros. The blocksize is 1024. So the first extend block contains the following information:
eh_entries: 1
eh_depth: 1
ei_block 1
When the upper layer (ext4fs_read_file) asks for fileblock 0, we are running in the 'invalid extent' error message.
For me it seems, that the code is not prepared for handling a sparse block at the beginning of the file. The following change, solved my problem:
I am really not an expert in ext4 filesystems. Can somebody please have a look at this issue and give me a feedback, if I am totally wrong or not?
Re-use the functions used to write/create a file, to support creation of a
symbolic link.
The difference with a regular file are small:
- The inode mode is flagged with S_IFLNK instead of S_IFREG
- The ext2_dirent's filetype is FILETYPE_SYMLINK instead of FILETYPE_REG
- Instead of storing the content of a file in allocated blocks, the path
to the target is stored. And if the target's path is short enough, no block
is allocated and the target's path is stored in ext2_inode.b.symlink
As with regulars files, if a file/symlink with the same name exits, it is
unlinked first and then re-created.
Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
[trini: Fix ext4 env code]
Signed-off-by: Tom Rini <trini@konsulko.com>
There is no need to modify the buffer passed to ext4fs_write_file().
The memset() call is not required here and was likely copied from the
equivalent part of the ext4fs_read_file() function where we do need it.
Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
When a file contains extents, U-Boot currently reads extent-related data
for each block in the file, even if that data is located in the same
block each time. This significantly slows down loading of files that use
extents. Implement a very dumb cache to prevent repeatedly reading the
same block. Files with extents now load as fast as files without.
Note: There are many cases where read_allocated_block() is called. This
patch only addresses one of those places; all others still read redundant
data in any case they did before. This is a minimal patch to fix the
load command; other cases aren't fixed.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
In int-ll64.h, we always use the following typedefs:
typedef unsigned int u32;
typedef unsigned long uintptr_t;
typedef unsigned long long u64;
This does not need to match to the compiler's <inttypes.h>.
Do not include it.
The use of PRI* makes the code super-ugly. You can simply use
"l" for printing uintptr_t, "ll" for u64, and no modifier for u32.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
When U-Boot started using SPDX tags we were among the early adopters and
there weren't a lot of other examples to borrow from. So we picked the
area of the file that usually had a full license text and replaced it
with an appropriate SPDX-License-Identifier: entry. Since then, the
Linux Kernel has adopted SPDX tags and they place it as the very first
line in a file (except where shebangs are used, then it's second line)
and with slightly different comment styles than us.
In part due to community overlap, in part due to better tag visibility
and in part for other minor reasons, switch over to that style.
This commit changes all instances where we have a single declared
license in the tag as both the before and after are identical in tag
contents. There's also a few places where I found we did not have a tag
and have introduced one.
Signed-off-by: Tom Rini <trini@konsulko.com>
Some fixes when reading EXT files and directory entries were identified
after using e2fuzz to corrupt an EXT3 filesystem:
- Stop reading directory entries if the offset becomes badly aligned.
- Avoid overwriting memory by clamping the length used to zero the buffer
in ext4fs_read_file. Also sanity check blocksize.
Signed-off-by: Ian Ray <ian.ray@ge.com>
Signed-off-by: Martyn Welch <martyn.welch@collabora.co.uk>
Reviewed-by: Stefano Babic <sbabic@denx.de>
The current code doesn't compute the group descriptor checksum correctly
for the filesystems that e2fsprogs 1.43.4 creates (they have
'Group descriptor size: 64' as reported by tune2fs). Extend the checksum
calculation to be done as ext4_group_desc_csum() does in Linux.
This fixes these errors in dmesg from running fs-test.sh and makes it
succeed again:
[1671902.620699] EXT4-fs (loop1): ext4_check_descriptors: Checksum for group 0 failed (35782!=10965)
[1671902.620706] EXT4-fs (loop1): group descriptors corrupted!
Signed-off-by: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
genext2fs creates revision level 0 filesystems, which are not readable
by u-boot due to the initialized group descriptor size field.
f798b1dda1
Reported-by: Kever Yang <kever.yang@rock-chips.com>
Reported-by: FrostyBytes@protonmail.com
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Tested-by: Kever Yang <kever.yang@rock-chips.com>
A sparse file may have regions not mapped by any extents, at the start
or at the end of the file, or anywhere between, thus not finding a
matching extent region is never an error.
Found by python filesystem tests.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Instead of creating a journal entry for each directory block, even
if the block is unmodified, only log the modified block.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
The direntlen checks were quite bogus, i.e. the loop termination used
"len + offset == blocksize" (exact match only), and checked for a
direntlen less than 0. The latter can never happen as the len is
unsigned, this has been reported by Coverity, CID 153384.
Use the same code as in search_dir for directory traversal. This code
has the correct checks for direntlen >= sizeof(struct dirent), and
offset < blocksize.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reported-by: Coverity (CID: 153383, 153384)
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
Use the same variable names as in search_dir, to make purpose of variables
more obvious.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
Enable mounting of ext4 fs with 64bit feature, as it is supported now.
These had been disabled in 6f94ab6656.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
The descriptor size is variable, thus array indices are not generically
applicable. The larger group descriptors also contain e.g. high parts
of block numbers, which have to be read and written.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
The correct descriptor size must be used when calculating offsets, and
also to read the correct amount of data.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
The helper functions encapsulate access of the block group descriptors,
independent of group descriptor size. The helpers also deal with the
endianess of the fields, and with split fields like free_blocks/
free_blocks_high.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
If EXT4_FEATURE_INCOMPAT_64BIT is set, the descriptor can be read from
the superblocks, otherwise it defaults to 32.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
read_allocated block may return block number 0, which is just an indicator
a chunk of the file is not backed by a block, i.e. it is sparse.
During file deletions, just continue with the next logical block, for other
operations treat blocknumber <= 0 as an error.
For writes, blocknumber 0 should never happen, as U-Boot always allocates
blocks for the whole file. Reading already handles this correctly, i.e. the
read buffer is 0-fillled.
Not treating block 0 as sparse block leads to FS corruption, e.g.
./sandbox/u-boot -c 'host bind 0 ./sandbox/test/fs/3GB.ext4.img ;
ext4write host 0 0 /2.5GB.file 1 '
The 2.5GB.file from the fs test is actually a sparse file.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
If the blocksize is 1024, count is initialized with 1. Incrementing count
by 8 will never match (count == fs->blksz * 8), and ptr may be
incremented beyond the buffer end if the bitmap is filled. Add the
startblock offset after the loop.
Remove the second loop, as only the first iteration will be done.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
The last free block of a block group may be in its middle. After it has
been allocated, the next block group should be scanned from its beginning.
The following command triggers the bad behaviour (on a blocksize 1024 fs):
./sandbox/u-boot -c 'i=0; host bind 0 ./disk.raw ;
while test $i -lt 260 ; do echo $i; setexpr i $i + 1;
ext4write host 0:2 0 /X${i} 0x1450; done ;
ext4write host 0:2 0 /X240 0x2000 ; '
When 'X240' is extended from 5200 byte to 8192 byte, the new blocks should
start from the first free block (8811), but it uses the blocks 8098-8103
and 16296-16297 -- 8103 + 1 + 8192 = 16296. This can be shown with
debugfs, commands 'ffb' and 'stat X240'.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
zero_buffer is never written, thus clearing it is pointless.
journal_buffer is completely initialized by ext4fs_devread (or in case
of failure, not used).
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
e2fsck warns about "Group descriptor 0 marked uninitialized without
feature set."
The bg_itable_unused field is only defined if FEATURE_RO_COMPAT_GDT_CSUM
is set, and should be set (kept) zero otherwise.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
Scanning only the direct blocks of the directory file may falsely report
an existing file as nonexisting, and worse can also lead to creation
of a duplicate entry on file creation.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
Previously, only the last directory block was scanned for available space.
Instead, scan all blocks back to front, and if no sufficient space is
found, eventually append a new block.
Blocks are only appended if the directory does not use extents or the new
block would require insertion of indirect blocks, as the old code does.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
The following command crashes u-boot:
./sandbox/u-boot -c 'i=0; host bind 0 ./sandbox/test/fs/3GB.ext4.img ;
while test $i -lt 200 ; do echo $i; setexpr i $i + 1;
ext4write host 0 0 /foobar${i} 0; done'
Previously, the code updated the direct_block even for extents, and
fortunately crashed before pushing garbage to the disk.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
In case the dir entry creation failed, ext4fs_write would later overwrite
a random inode, as inodeno was never initialized.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
The following command triggers a segfault in search_dir:
./sandbox/u-boot -c 'host bind 0 ./sandbox/test/fs/3GB.ext4.img ;
ext4write host 0 0 /./foo 0x10'
The following command triggers a segfault in check_filename:
./sandbox/u-boot -c 'host bind 0 ./sandbox/test/fs/3GB.ext4.img ;
ext4write host 0 0 /. 0x10'
"." is the first entry in the directory, thus previous_dir is NULL. The
whole previous_dir block in search_dir seems to be a bad copy from
check_filename(...). As the changed data is not written to disk, the
statement is mostly harmless, save the possible NULL-ptr reference.
Typically a file is unlinked by extending the direntlen of the previous
entry. If the entry is the first entry in the directory block, it is
invalidated by setting inode=0.
The inode==0 case is hard to trigger without crafted filesystems. It only
hits if the first entry in a directory block is deleted and later a lookup
for the entry (by name) is done.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>