ext2simg: fix off-by-one errors causing corruption

The chunk_end parameter to add_chunk() is exclusive, but two callers
incorrectly treat it as inclusive: when the maximum chunk length of
'INT32_MAX - 12' bytes is reached, and when a chunk extends to the very
end of the filesystem.  The result is that the output simg file contains
zeroes for the last block of these chunks instead of the correct data.

A related bug is that the expanded size of the simg file is set to the
filesystem size (in blocks) minus s_first_data_block.  On filesystems
where s_first_data_block != 0, i.e. 1K blocksize filesystems without
bigalloc enabled, this truncates the last block of the filesystem.

Fix these bugs by (a) making add_chunk() take the chunk length and
passing the correct values, and (b) using the filesystem size properly.

Here is a reproducer that shows the last block of the filesystem being
truncated (bsize=1024) and being corrupted with zeroes (bsize=4096):

    for bsize in 1024 4096; do
        rm -f ext4.img
        mkfs.ext4 -b $bsize ext4.img 10000
        mkdir -p mnt
        sudo mount -t ext4 -o loop ext4.img mnt
        sudo cp /dev/urandom mnt/fill
        sudo umount mnt
        ext2simg ext4.img ext4.simg
        simg2img ext4.simg ext4.img.restored
        cmp ext4.img ext4.img.restored
    done

Fixes: db6f320912cf ("AOSP: android: add the ext2simg tool")
Reported-by: Clemens Lang <clemens.lang@bmw.de>
Change-Id: I3b64c4fbffa5821b431f29e99b36168617da7563
Signed-off-by: Eric Biggers <ebiggers@google.com>
1 file changed