gerard / ext4fuse

EXT4 implementation for FUSE
GNU General Public License v2.0
913 stars 110 forks source link

Fix assertion when sparse files don't end on a block boundary #51

Closed cernekee closed 6 years ago

cernekee commented 6 years ago

op_read() can fail an assertion if the last block of a file is sparse and the file length does not divide evenly by the block size. Test case:

wget https://dl.google.com/dl/android/aosp/blueline-pd1a.180720.030-factory-d6fefe86.zip
unzip blueline-pd1a.180720.030-factory-d6fefe86.zip
unzip blueline-pd1a.180720.030/image-blueline-pd1a.180720.030.zip vendor.img
simg2img vendor.img vendor.img.raw
mkdir vendor
ext4fuse vendor.img.raw vendor
sha1sum vendor/firmware/confirmationui.b04

The log reports:

[debug][op_read:110] Read 12288/12421 bytes from 1 consecutive blocks
[debug][extent_get_block_from_ees:23] Extent contains 1 entries
[debug][extent_get_block_from_ees:24] Looking for LBlock 259
[debug][extent_get_block_from_ees:39] Extent [0] doesn't contain block
[debug][op_read:106] sparse file, skipping 4096 bytes
[debug][op_read:110] Read 16384/12421 bytes from 1 consecutive blocks
[warn] [op_read:114] ASSERT FAIL: size == ret

The sha1sum command (and further operations on the filesystem) fail with ENOTCONN.

This filesystem uses 4kB blocks. Offsets 0x20220 - 0x103084 of the file are all zeroes; therefore only blocks 0-32 are present on disk:

debugfs:  stat /firmware/confirmationui.b04
Inode: 568   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 0    Version: 0x00000000:00000000
User:     0   Group:     0   Project:     0   Size: 1060997
File ACL: 0
Links: 1   Blockcount: 264
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x495c7800:00000000 -- Thu Jan  1 00:00:00 2009
 atime: 0x495c7800:00000000 -- Thu Jan  1 00:00:00 2009
 mtime: 0x495c7800:00000000 -- Thu Jan  1 00:00:00 2009
crtime: 0x495c7800:00000000 -- Thu Jan  1 00:00:00 2009
Size of extra inode fields: 32
Extended attributes:
  security.selinux (26) = "u:object_r:vendor_file:s0\000"
EXTENTS:
(0-32):12468-12500

debugfs:  blocks /firmware/confirmationui.b04
12468 12469 12470 12471 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499 12500

hexdump -C confirmationui.b04 ends with:

00020210  00 00 00 00 00 00 00 00  00 00 00 ff ff ff ff ff  |................|
00020220  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00103085

Change op_read() so that it takes the remaining transfer bytes into account instead of always returning |BLOCK_SIZE| zeroes when reading a sparse block.

I also added a new check to test case 0014 to catch this error.