From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) by mx.groups.io with SMTP id smtpd.web10.2659.1683593708342281575 for ; Mon, 08 May 2023 17:55:08 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="signature has expired" header.i=@gmail.com header.s=20221208 header.b=GAN80Its; spf=pass (domain: gmail.com, ip: 209.85.221.47, mailfrom: pedro.falcato@gmail.com) Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-3063891d61aso4951859f8f.0 for ; Mon, 08 May 2023 17:55:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1683593706; x=1686185706; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=OpoO4Q0eJvtqgWRGjsU0szNWT9GzuXCwwDzIkqynopE=; b=GAN80ItsXMidcBa7AOUj4kyAOj3ldrPkPxsZ6dlIq4VwfxYw1CZNM/QYEQQNI8JPUp 7XlA/7Wit1pmW0hwZGZehJIKctzUdOTn5zWDycF65VpSRXdeF6riq6mm6cqXX9fiTNnz 5WHGyxGB7TJAJu2+TgxZNsTjPFtp2PrksNVIktcmCbIInhA7rvgSXvfZ19J+AQk9gG1i O71A/ZvIdTtgdWhnzVuAS2uvqhwwDECDFt9Rz1KzY0Iqw8lwTBnDAoB7ZwpNmcyH6rCQ GlmUDxnITszIgMaefCVpryWvr+VTsELAiRsn/tcGp0vFTJxD1niOHJjdvx5+vcI+g/QH S0Lg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683593706; x=1686185706; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=OpoO4Q0eJvtqgWRGjsU0szNWT9GzuXCwwDzIkqynopE=; b=ixtQCi4mi825XYDGFp7YfixEJhv7aDcwy5ZN6KXRWGTvbQWUbI46woAwKC3xKZr4gJ ouZNF4kW1TbXGObY0n99h6mGmLrZz/KSA63BPYWvrpenoMktctPj136zeO+2QaYm7WxZ p7w7IoGK9uWIHuozGI34Ym5nXlIrxFhk36GaGicqiAxJxkcBf21PO+kC0VQtRfwKErlD VhPzq+4ZgNkQjJsW0Rlh0yWbeMweUS/y3C+LQI1Mf6QErUhflqYpe07k+ndEg3BS5U5S x4HRzUC33kt0wNzAf2xcYSdz7ybqEy2oOKYGFx6aFn2Bd62NDALWJCKvGjIFKgw9ElBv hthA== X-Gm-Message-State: AC+VfDyv9opnhZrkR5PhuedOG0OETBJb/ZMBEgn80E9TiVMwAifweCvb +EPSfZELdUVn/nMz6o4nHFmP+8JU3LoiQYDy X-Google-Smtp-Source: ACHHUZ5akznj2i8XGEdHtESVqBACNINYSfi2Uy+KVGeBSFJYzs3+wDs3bh+5pV2+8ciTVtnruG+u+w== X-Received: by 2002:a5d:5266:0:b0:2e9:bb2f:ce03 with SMTP id l6-20020a5d5266000000b002e9bb2fce03mr9181676wrc.0.1683593706055; Mon, 08 May 2023 17:55:06 -0700 (PDT) Return-Path: Received: from PC-PEDRO-ARCH.lan ([2001:8a0:7280:5801:9441:3dce:686c:bfc7]) by smtp.gmail.com with ESMTPSA id k15-20020a5d518f000000b003077a19cf75sm12560770wrv.60.2023.05.08.17.55.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 May 2023 17:55:05 -0700 (PDT) From: "Pedro Falcato" To: devel@edk2.groups.io Cc: Pedro Falcato , =?UTF-8?q?Marvin=20H=C3=A4user?= , Savva Mitrofanov Subject: [PATCH v2 1/2] Ext4Pkg: Improve extent node validation on the number of entries Date: Tue, 9 May 2023 01:54:57 +0100 Message-Id: <20230509005458.245291-1-pedro.falcato@gmail.com> X-Mailer: git-send-email 2.40.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve the extent tree node validation by validating the number of entries the node advertises against the theoretical max (derived from the size of on-disk structs and the block size (or i_data, if inline extents). Previously, we did not validate the number of entries. This could be exploited for out-of-bounds reads and crashes. Cc: Marvin Häuser Fixes: d9ceedca6c8f ("Ext4Pkg: Add Ext4Dxe driver.") Reported-by: Savva Mitrofanov Signed-off-by: Pedro Falcato --- v2: Accidentally based my previous patch on the wrong version of Extents.c, which accidentally undid some previous changes. Features/Ext4Pkg/Ext4Dxe/Extents.c | 32 ++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Features/Ext4Pkg/Ext4Dxe/Extents.c b/Features/Ext4Pkg/Ext4Dxe/Extents.c index 9e4364e50d99..2d86a7abdedb 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Extents.c +++ b/Features/Ext4Pkg/Ext4Dxe/Extents.c @@ -1,7 +1,7 @@ /** @file Extent related routines - Copyright (c) 2021 - 2022 Pedro Falcato All rights reserved. + Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -80,13 +80,15 @@ Ext4GetInoExtentHeader ( /** Checks if an extent header is valid. @param[in] Header Pointer to the EXT4_EXTENT_HEADER structure. + @param[in] MaxEntries Maximum number of entries possible for this tree node. @return TRUE if valid, FALSE if not. **/ STATIC BOOLEAN Ext4ExtentHeaderValid ( - IN CONST EXT4_EXTENT_HEADER *Header + IN CONST EXT4_EXTENT_HEADER *Header, + IN UINT16 MaxEntries ) { if (Header->eh_depth > EXT4_EXTENT_TREE_MAX_DEPTH) { @@ -99,6 +101,18 @@ Ext4ExtentHeaderValid ( return FALSE; } + if ((Header->eh_max > MaxEntries) || (Header->eh_entries > MaxEntries)) { + DEBUG (( + DEBUG_ERROR, + "[ext4] Invalid extent header entries (extent header: %u max," + " %u entries, theoretical max: %u) (larger than permitted)\n", + Header->eh_max, + Header->eh_entries, + MaxEntries + )); + return FALSE; + } + if (Header->eh_max < Header->eh_entries) { DEBUG (( DEBUG_ERROR, @@ -212,6 +226,9 @@ Ext4ExtentIdxLeafBlock ( return LShiftU64 (Index->ei_leaf_hi, 32) | Index->ei_leaf_lo; } +// Results of sizeof(i_data) / sizeof(extent) - 1 = 4 +#define EXT4_NR_INLINE_EXTENTS 4 + /** Retrieves an extent from an EXT4 inode. @param[in] Partition Pointer to the opened EXT4 partition. @@ -237,6 +254,7 @@ Ext4GetExtent ( EXT4_EXTENT_HEADER *ExtHeader; EXT4_EXTENT_INDEX *Index; EFI_STATUS Status; + UINT32 MaxExtentsPerNode; EXT4_BLOCK_NR BlockNumber; Inode = File->Inode; @@ -275,12 +293,17 @@ Ext4GetExtent ( ExtHeader = Ext4GetInoExtentHeader (Inode); - if (!Ext4ExtentHeaderValid (ExtHeader)) { + if (!Ext4ExtentHeaderValid (ExtHeader, EXT4_NR_INLINE_EXTENTS)) { return EFI_VOLUME_CORRUPTED; } CurrentDepth = ExtHeader->eh_depth; + // A single node fits into a single block, so we can only have (BlockSize / sizeof(EXT4_EXTENT)) - 1 + // extents in a single node. Note the -1, because both leaf and internal node headers are 12 bytes, + // and so are individual entries. + MaxExtentsPerNode = (Partition->BlockSize / sizeof (EXT4_EXTENT)) - 1; + while (ExtHeader->eh_depth != 0) { CurrentDepth--; // While depth != 0, we're traversing the tree itself and not any leaves @@ -309,6 +332,7 @@ Ext4GetExtent ( } // Read the leaf block onto the previously-allocated buffer. + Status = Ext4ReadBlocks (Partition, Buffer, 1, BlockNumber); if (EFI_ERROR (Status)) { FreePool (Buffer); @@ -317,7 +341,7 @@ Ext4GetExtent ( ExtHeader = Buffer; - if (!Ext4ExtentHeaderValid (ExtHeader)) { + if (!Ext4ExtentHeaderValid (ExtHeader, MaxExtentsPerNode)) { FreePool (Buffer); return EFI_VOLUME_CORRUPTED; } -- 2.40.1