From ed668ba5969a260cbef4d24ce44ac4eddd49d761 Mon Sep 17 00:00:00 2001 From: Savva Mitrofanov Date: Fri, 28 Oct 2022 18:09:37 +0600 Subject: [PATCH] Ext4Pkg: Fix shift out of bounds in Ext4OpenSuperblock Missing check for wrong s_log_block_size exponent leads to shift out of bounds. Limit block size to 2 MiB Signed-off-by: Savva Mitrofanov --- Ext4Pkg/Ext4Dxe/Ext4Dxe.h | 14 ++++++++++++++ Ext4Pkg/Ext4Dxe/Superblock.c | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Ext4Pkg/Ext4Dxe/Ext4Dxe.h index d135892633..0600a75d67 100644 --- a/Ext4Pkg/Ext4Dxe/Ext4Dxe.h +++ b/Ext4Pkg/Ext4Dxe/Ext4Dxe.h @@ -40,6 +40,20 @@ #define EXT4_EFI_PATH_MAX 4096 #define EXT4_DRIVER_VERSION 0x0000 +// +// The EXT4 Specification doesn't strictly limit block size and this value could be up to 2^31, +// but in practice it is limited by PAGE_SIZE due to performance significant impact. +// Many EXT4 implementations have size of block limited to PAGE_SIZE. In many cases it's limited +// to 4096, which is a commonly supported page size on most MMU-capable hardware, and up to 65536. +// So, to take a balance between compatibility and security measures, it is decided to use the +// value of 2MiB as the limit, which is equal to page size on new hardware. +// As for supporting big block sizes, EXT4 has a RO_COMPAT_FEATURE called BIGALLOC, which changes +// EXT4 to use clustered allocation, so that each bit in the ext4 block allocation bitmap addresses +// a power of two number of blocks. So it would be wiser to implement and use this feature +// if there is such a need instead of big block size. +// +#define EXT4_LOG_BLOCK_SIZE_MAX 11 + /** Opens an ext4 partition and installs the Simple File System protocol. diff --git a/Ext4Pkg/Ext4Dxe/Superblock.c b/Ext4Pkg/Ext4Dxe/Superblock.c index adaf475ea5..ffe66a8bb8 100644 --- a/Ext4Pkg/Ext4Dxe/Superblock.c +++ b/Ext4Pkg/Ext4Dxe/Superblock.c @@ -248,6 +248,11 @@ Ext4OpenSuperblock ( return EFI_VOLUME_CORRUPTED; } + if (Sb->s_log_block_size > EXT4_LOG_BLOCK_SIZE_MAX) { + DEBUG ((DEBUG_ERROR, "[ext4] SuperBlock s_log_block_size %lu is too big\n", Sb->s_log_block_size)); + return EFI_UNSUPPORTED; + } + Partition->BlockSize = (UINT32)LShiftU64 (1024, Sb->s_log_block_size); // The size of a block group can also be calculated as 8 * Partition->BlockSize