summaryrefslogtreecommitdiff
path: root/ext4_utils
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2020-10-20 09:36:45 -0700
committerEric Biggers <ebiggers@google.com>2020-10-20 10:05:37 -0700
commit07a7c53c4516534fae2c7fbf530517a05a77fe0a (patch)
treec005a854b0d3dd0072bb0184b7e5909cb542af2d /ext4_utils
parentbc8a4a3be6c779c01555858b641214eec80bad85 (diff)
downloadextras-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.cpp3
-rw-r--r--ext4_utils/ext4_utils.cpp58
-rw-r--r--ext4_utils/include/ext4_utils/ext4_sb.h1
-rw-r--r--ext4_utils/include/ext4_utils/ext4_utils.h15
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 {