diff options
author | Eric Biggers <ebiggers@google.com> | 2020-10-20 09:36:45 -0700 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2020-10-20 10:05:37 -0700 |
commit | 07a7c53c4516534fae2c7fbf530517a05a77fe0a (patch) | |
tree | c005a854b0d3dd0072bb0184b7e5909cb542af2d /ext4_utils | |
parent | bc8a4a3be6c779c01555858b641214eec80bad85 (diff) | |
download | extras-07a7c53c4516534fae2c7fbf530517a05a77fe0a.tar.gz |
ext4_utils: correctly read block group descriptors on 64bit filesystems
ext4_utils isn't aware of filesystems with the "64bit" feature. The
64bit feature changes the filesystem-wide block numbers to be 64-bit
instead of 32-bit, and it increases the size of the block group
descriptors. Apparently we've gotten away with this until now since
ext4 filesystems in Android haven't been using the 64bit feature.
However, change I618a65d7afc63a617f5f2582c93002af7f8e7234 added support
for the metadata_csum feature, and Android enables 64bit whenever
metadata_csum is enabled because it improves the usefulness of
metadata_csum. Separately, when Cuttlefish is configured to use ext4
and 'launch_cvd -data_policy always_create' is used, the filesystem ends
up with the 64bit feature because the host's mke2fs.conf is used.
vold's encrypt-in-place code doesn't work correctly on 64bit
filesystems, since it uses the block group descriptors to identify
in-use blocks, and ext4_utils mis-reads the descriptors such that
descriptor 'i' gets read into the structs for descriptors 2*i and 2*i+1.
Note that this is a problem even if the filesystem doesn't contain more
than 2^32 blocks (which can still be assumed to be true on Android).
So, fix ext4_utils to correctly read the block group descriptors on both
64bit and !64bit filesystems.
Test: Booted Cuttlefish with ext4 + metadata encryption, both with and
without the 64bit feature. Before, it only worked with !64bit.
Change-Id: I0682971e022407f43ccb3b08c997b787d1a9e649
Diffstat (limited to 'ext4_utils')
-rw-r--r-- | ext4_utils/ext4_sb.cpp | 3 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.cpp | 58 | ||||
-rw-r--r-- | ext4_utils/include/ext4_utils/ext4_sb.h | 1 | ||||
-rw-r--r-- | ext4_utils/include/ext4_utils/ext4_utils.h | 15 |
4 files changed, 60 insertions, 17 deletions
diff --git a/ext4_utils/ext4_sb.cpp b/ext4_utils/ext4_sb.cpp index 5c3e4f3f..4183b3aa 100644 --- a/ext4_utils/ext4_sb.cpp +++ b/ext4_utils/ext4_sb.cpp @@ -34,6 +34,9 @@ int ext4_parse_sb(struct ext4_super_block *sb, struct fs_info *info) info->feat_compat = sb->s_feature_compat; info->feat_incompat = sb->s_feature_incompat; info->bg_desc_reserve_blocks = sb->s_reserved_gdt_blocks; + info->bg_desc_size = + (sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? + sb->s_desc_size : EXT4_MIN_DESC_SIZE; info->label = sb->s_volume_name; len_blocks = ((uint64_t)sb->s_blocks_count_hi << 32) + diff --git a/ext4_utils/ext4_utils.cpp b/ext4_utils/ext4_utils.cpp index 5175efc0..234ceeb6 100644 --- a/ext4_utils/ext4_utils.cpp +++ b/ext4_utils/ext4_utils.cpp @@ -120,8 +120,7 @@ void ext4_create_fs_aux_info() aux_info.blocks_per_tind = aux_info.blocks_per_dind * aux_info.blocks_per_dind; aux_info.bg_desc_blocks = - DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc), - info.block_size); + DIV_ROUND_UP(aux_info.groups * (size_t)info.bg_desc_size, info.block_size); aux_info.default_i_flags = EXT4_NOATIME_FL; @@ -166,7 +165,8 @@ void ext4_create_fs_aux_info() if (!aux_info.sb) critical_error_errno("calloc"); - aux_info.bg_desc = (struct ext2_group_desc *)calloc(info.block_size, aux_info.bg_desc_blocks); + aux_info.bg_desc = + (struct ext2_group_desc *)calloc(aux_info.groups, sizeof(struct ext2_group_desc)); if (!aux_info.bg_desc) critical_error_errno("calloc"); aux_info.xattrs = NULL; @@ -266,6 +266,51 @@ u64 get_file_size(int fd) return computed_size; } +static void read_block_group_descriptors(int fd) +{ + size_t size = info.block_size * (size_t)aux_info.bg_desc_blocks; + void *buf = malloc(size); + ssize_t ret; + + if (!buf) + critical_error("failed to alloc buffer"); + + ret = read(fd, buf, size); + if (ret < 0) { + free(buf); + critical_error_errno("failed to read block group descriptors"); + } + if (ret != size) { + free(buf); + critical_error("failed to read all the block group descriptors"); + } + const struct ext4_group_desc *gdp = (const struct ext4_group_desc *)buf; + bool extended = (info.bg_desc_size >= EXT4_MIN_DESC_SIZE_64BIT); + for (size_t i = 0; i < aux_info.groups; i++) { + aux_info.bg_desc[i].bg_block_bitmap = + (extended ? (u64)gdp->bg_block_bitmap_hi << 32 : 0) | + gdp->bg_block_bitmap_lo; + aux_info.bg_desc[i].bg_inode_bitmap = + (extended ? (u64)gdp->bg_inode_bitmap_hi << 32 : 0) | + gdp->bg_inode_bitmap_lo; + aux_info.bg_desc[i].bg_inode_table = + (extended ? (u64)gdp->bg_inode_table_hi << 32 : 0) | + gdp->bg_inode_table_lo; + aux_info.bg_desc[i].bg_free_blocks_count = + (extended ? (u32)gdp->bg_free_blocks_count_hi << 16 : 0) | + gdp->bg_free_blocks_count_lo; + aux_info.bg_desc[i].bg_free_inodes_count = + (extended ? (u32)gdp->bg_free_inodes_count_hi << 16 : 0) | + gdp->bg_free_inodes_count_lo; + aux_info.bg_desc[i].bg_used_dirs_count = + (extended ? (u32)gdp->bg_used_dirs_count_hi << 16 : 0) | + gdp->bg_used_dirs_count_lo; + aux_info.bg_desc[i].bg_flags = gdp->bg_flags; + gdp = (const struct ext4_group_desc *)((u8 *)gdp + info.bg_desc_size); + } + free(buf); +} + int read_ext(int fd, int verbose) { off64_t ret; @@ -283,11 +328,7 @@ int read_ext(int fd, int verbose) if (ret < 0) critical_error_errno("failed to seek to block group descriptors"); - ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks); - if (ret < 0) - critical_error_errno("failed to read block group descriptors"); - if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks) - critical_error("failed to read all of block group descriptors"); + read_block_group_descriptors(fd); if (verbose) { printf("Found filesystem with parameters:\n"); @@ -300,6 +341,7 @@ int read_ext(int fd, int verbose) printf(" Blocks: %" PRIext4u64 "\n", aux_info.len_blocks); printf(" Block groups: %d\n", aux_info.groups); printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); + printf(" Block group descriptor size: %d\n", info.bg_desc_size); printf(" Used %d/%d inodes and %d/%d blocks\n", aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, aux_info.sb->s_inodes_count, diff --git a/ext4_utils/include/ext4_utils/ext4_sb.h b/ext4_utils/include/ext4_utils/ext4_sb.h index ab8b42f7..3b53dbe4 100644 --- a/ext4_utils/include/ext4_utils/ext4_sb.h +++ b/ext4_utils/include/ext4_utils/ext4_sb.h @@ -43,6 +43,7 @@ struct fs_info { uint32_t feat_compat; uint32_t feat_incompat; uint32_t bg_desc_reserve_blocks; + uint16_t bg_desc_size; const char *label; uint8_t no_journal; bool block_device; /* target fd is a block device? */ diff --git a/ext4_utils/include/ext4_utils/ext4_utils.h b/ext4_utils/include/ext4_utils/ext4_utils.h index f5cfa2ab..2c2485f7 100644 --- a/ext4_utils/include/ext4_utils/ext4_utils.h +++ b/ext4_utils/include/ext4_utils/ext4_utils.h @@ -85,16 +85,13 @@ struct block_group_info; struct xattr_list_element; struct ext2_group_desc { - u32 bg_block_bitmap; - u32 bg_inode_bitmap; - u32 bg_inode_table; - u16 bg_free_blocks_count; - u16 bg_free_inodes_count; - u16 bg_used_dirs_count; + u64 bg_block_bitmap; + u64 bg_inode_bitmap; + u64 bg_inode_table; + u32 bg_free_blocks_count; + u32 bg_free_inodes_count; + u32 bg_used_dirs_count; u16 bg_flags; - u32 bg_reserved[2]; - u16 bg_reserved16; - u16 bg_checksum; }; struct fs_aux_info { |