Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Nov 10, 2018

Conversation

cernekee
Copy link
Contributor

@cernekee cernekee commented Oct 31, 2018

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.

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.
By default, the new filesystem will only be root-writable.  Change
the ownership so that test cases can run as a normal user.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants