From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-lf1-f44.google.com (mail-lf1-f44.google.com [209.85.167.44]) by mx.groups.io with SMTP id smtpd.web11.50531.1658295383953630287 for ; Tue, 19 Jul 2022 22:36:24 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20210112 header.b=qXUPCsaK; spf=pass (domain: gmail.com, ip: 209.85.167.44, mailfrom: savvamtr@gmail.com) Received: by mail-lf1-f44.google.com with SMTP id o7so28455866lfq.9 for ; Tue, 19 Jul 2022 22:36:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=rPLHyFKjgklkfHZ4yY3KctRlYI5GSMaA0C34Z7mTB2M=; b=qXUPCsaK0kuM58R9GL8dM3g7T5k0o7qpHQVKsFdog9DvnQWslrTEUK2ZzUcaoA722j 0C6KVDcInbib5AE/Tu5ZgNFpGzkxH8KIjsntpf5GpuNOZhY02wBVPPJ8z6eFf0CIa4Il fyLqjUtuQBX9VmPKCBhyH/KDk8Y8aNiGRNT6d7++Gi2G3DJ4lmpZQHeQLWYlTEwhwBBL VacxeRBfKBQvvWDoVP+gNqYaMHv6Xz1IRofdr4AIjUg6+bGl8ZM9Y5DL2tjNEQJpXJJo +W1y2qrEEpws1USQRkPV1FobXF4wGm1o134aEhLqkkshCElggAs25lYG2GgrGZnxGgKs eh0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rPLHyFKjgklkfHZ4yY3KctRlYI5GSMaA0C34Z7mTB2M=; b=giesD5MBqKPlfXycjzw5+sY7M0C+QDujGzl4m4cnv3eJiXCYFh0bvYHKTUTOVT1Uab cFlks0++C0vdjq9vhRajnfC0CPYeYEqgTry3BL8G1S+NFR16PxvZNUwCbd9ZhcRJv3Lj OBfPM3qJdoFejuMwkO68UokkTIOuHvZSjHNveLIgpoHy9uk3SAOHFPRFWi3afwxlLnrJ uML0870ZqttUS7gwZnQ81YrjsXf2AidPoyPvc70LQqcy+pxbBwoM2ZfGnoExPF1sIRpe enODja1YqxYUVQeKhKbhoFawCoBYeqJoeYZBgwArWyAl6PUfW4bPeoe7nS79yn4HSqLU e2ZA== X-Gm-Message-State: AJIora8o6asus8RutYgT0BuTB5RJOx92xGNm5ARZIBp/bvvXSnNHeN+y 6n+AdaXSmiQqOuwgIYRQKDyQFEURlXt+8Iu4Tp4= X-Google-Smtp-Source: AGRyM1up1raxqq83KoGsvF6tM9kO04FJCc7LVOURkqk0atMp0Vto8DWHG1fnVEUscVBtgEngNIRQVg== X-Received: by 2002:a05:6512:ea8:b0:48a:1ec9:8396 with SMTP id bi40-20020a0565120ea800b0048a1ec98396mr13386062lfb.445.1658295381981; Tue, 19 Jul 2022 22:36:21 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([207.180.219.167]) by smtp.gmail.com with ESMTPSA id 13-20020a05651c128d00b0025d39993856sm2995023ljc.127.2022.07.19.22.36.20 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 19 Jul 2022 22:36:21 -0700 (PDT) From: "Savva Mitrofanov" To: devel@edk2.groups.io Cc: =?UTF-8?q?Marvin=20H=C3=A4user?= , Pedro Falcato , Vitaly Cheptsov Subject: [edk2-platforms][PATCH v2 1/1] Ext4Pkg: Code correctness and security improvements Date: Wed, 20 Jul 2022 11:36:06 +0600 Message-Id: <20220720053606.38975-2-savvamtr@gmail.com> X-Mailer: git-send-email 2.37.0 In-Reply-To: <20220720053606.38975-1-savvamtr@gmail.com> References: <20220720053606.38975-1-savvamtr@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable This changes tends to improve security of code sections by fixing integer overflows, missing aligment checks, unsafe casts, also simplified some routines, fixed compiler warnings and corrected some code mistakes. - Set HoleLen to UINT64 to perform safe cast to UINTN in ternary operator at WasRead assignment. - Replace EXT4_BLOCK_NR with 32-bit EXT2_BLOCK_NR in BlockMap, because we consider BlockMap is 32-bit fs ext2/3 feature. - Replace UNREACHABLE with ASSERT (FALSE) in case of new checksum algorithms, due to it is an invariant violation rather than unreachable path. - Solve compiler warnings. Init all fields in gExt4BindingProtocol. Fix comparison of integer expressions of different signedness. - Field name_len has type CHAR8, while filename limit is 255 (EXT4_NAME_MAX), so because structure EXT4_DIR_ENTRY would be unchangeable in future, we could drop this check without any assertions - Simplify Ext4RemoveDentry logic by using IsNodeInList - Fix possible int overflow in Ext4ExtentsMapKeyCompare - Return bad block type in Ext4GetBlockpath - Adds 4-byte aligned check for superblock group descriptor size field Cc: Marvin H=C3=A4user Cc: Pedro Falcato Cc: Vitaly Cheptsov Signed-off-by: Savva Mitrofanov --- Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 3 +- Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h | 2 +- Features/Ext4Pkg/Ext4Dxe/BlockMap.c | 18 ++++++++---- Features/Ext4Pkg/Ext4Dxe/Directory.c | 29 ++------------------ Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c | 10 ++++--- Features/Ext4Pkg/Ext4Dxe/Extents.c | 5 ++-- Features/Ext4Pkg/Ext4Dxe/Inode.c | 8 +++--- Features/Ext4Pkg/Ext4Dxe/Superblock.c | 13 +++++---- 8 files changed, 38 insertions(+), 50 deletions(-) diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dxe= /Ext4Disk.h index a55cd2fa68ad..7a19d2f79d53 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h @@ -338,7 +338,7 @@ STATIC_ASSERT ( #define EXT4_TIND_BLOCK 14=0D #define EXT4_NR_BLOCKS 15=0D =0D -#define EXT4_GOOD_OLD_INODE_SIZE 128=0D +#define EXT4_GOOD_OLD_INODE_SIZE 128U=0D =0D typedef struct _Ext4_I_OSD2_Linux {=0D UINT16 l_i_blocks_high;=0D @@ -463,6 +463,7 @@ typedef struct { #define EXT4_EXTENT_MAX_INITIALIZED (1 << 15)=0D =0D typedef UINT64 EXT4_BLOCK_NR;=0D +typedef UINT32 EXT2_BLOCK_NR;=0D typedef UINT32 EXT4_INO_NR;=0D =0D // 2 is always the root inode number in ext4=0D diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/= Ext4Dxe.h index b1508482b0a7..b446488b2112 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h @@ -1165,7 +1165,7 @@ EFI_STATUS Ext4GetBlocks (=0D IN EXT4_PARTITION *Partition,=0D IN EXT4_FILE *File,=0D - IN EXT4_BLOCK_NR LogicalBlock,=0D + IN EXT2_BLOCK_NR LogicalBlock,=0D OUT EXT4_EXTENT *Extent=0D );=0D =0D diff --git a/Features/Ext4Pkg/Ext4Dxe/BlockMap.c b/Features/Ext4Pkg/Ext4Dxe= /BlockMap.c index 1a06ac9fbf86..2bc629fe9d38 100644 --- a/Features/Ext4Pkg/Ext4Dxe/BlockMap.c +++ b/Features/Ext4Pkg/Ext4Dxe/BlockMap.c @@ -70,7 +70,7 @@ UINTN Ext4GetBlockPath (=0D IN CONST EXT4_PARTITION *Partition,=0D IN UINT32 LogicalBlock,=0D - OUT EXT4_BLOCK_NR BlockPath[EXT4_MAX_BLOCK_PATH]=0D + OUT EXT2_BLOCK_NR BlockPath[EXT4_MAX_BLOCK_PATH]=0D )=0D {=0D // The logic behind the block map is very much like a page table=0D @@ -123,7 +123,7 @@ Ext4GetBlockPath ( break;=0D default:=0D // EXT4_TYPE_BAD_BLOCK=0D - return -1;=0D + break;=0D }=0D =0D return Type + 1;=0D @@ -213,12 +213,12 @@ EFI_STATUS Ext4GetBlocks (=0D IN EXT4_PARTITION *Partition,=0D IN EXT4_FILE *File,=0D - IN EXT4_BLOCK_NR LogicalBlock,=0D + IN EXT2_BLOCK_NR LogicalBlock,=0D OUT EXT4_EXTENT *Extent=0D )=0D {=0D EXT4_INODE *Inode;=0D - EXT4_BLOCK_NR BlockPath[EXT4_MAX_BLOCK_PATH];=0D + EXT2_BLOCK_NR BlockPath[EXT4_MAX_BLOCK_PATH];=0D UINTN BlockPathLength;=0D UINTN Index;=0D UINT32 *Buffer;=0D @@ -230,7 +230,7 @@ Ext4GetBlocks ( =0D BlockPathLength =3D Ext4GetBlockPath (Partition, LogicalBlock, BlockPath= );=0D =0D - if (BlockPathLength =3D=3D (UINTN)-1) {=0D + if (BlockPathLength - 1 =3D=3D EXT4_TYPE_BAD_BLOCK) {=0D // Bad logical block (out of range)=0D return EFI_NO_MAPPING;=0D }=0D @@ -272,7 +272,13 @@ Ext4GetBlocks ( }=0D }=0D =0D - Ext4GetExtentInBlockMap (Buffer, Partition->BlockSize / sizeof (UINT32),= BlockPath[BlockPathLength - 1], Extent);=0D + Ext4GetExtentInBlockMap (=0D + Buffer,=0D + Partition->BlockSize / sizeof (UINT32),=0D + BlockPath[BlockPathLength - 1],=0D + Extent=0D + );=0D +=0D FreePool (Buffer);=0D =0D return EFI_SUCCESS;=0D diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dx= e/Directory.c index 682f66ad5525..4441e6d192b6 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Directory.c +++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c @@ -74,7 +74,7 @@ Ext4ValidDirent ( }=0D =0D // Dirent sizes need to be 4 byte aligned=0D - if (Dirent->rec_len % 4) {=0D + if ((Dirent->rec_len % 4) !=3D 0) {=0D return FALSE;=0D }=0D =0D @@ -160,17 +160,6 @@ Ext4RetrieveDirent ( return EFI_VOLUME_CORRUPTED;=0D }=0D =0D - // Ignore names bigger than our limit.=0D -=0D - /* Note: I think having a limit is sane because:=0D - 1) It's nicer to work with.=0D - 2) Linux and a number of BSDs also have a filename limit of 255.=0D - */=0D - if (Entry->name_len > EXT4_NAME_MAX) {=0D - BlockOffset +=3D Entry->rec_len;=0D - continue;=0D - }=0D -=0D // Unused entry=0D if (Entry->inode =3D=3D 0) {=0D BlockOffset +=3D Entry->rec_len;=0D @@ -548,20 +537,8 @@ Ext4RemoveDentry ( IN OUT EXT4_DENTRY *ToBeRemoved=0D )=0D {=0D - EXT4_DENTRY *D;=0D - LIST_ENTRY *Entry;=0D - LIST_ENTRY *NextEntry;=0D -=0D - BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Parent->Children) {=0D - D =3D EXT4_DENTRY_FROM_DENTRY_LIST (Entry);=0D -=0D - if (D =3D=3D ToBeRemoved) {=0D - RemoveEntryList (Entry);=0D - return;=0D - }=0D - }=0D -=0D - DEBUG ((DEBUG_ERROR, "[ext4] Ext4RemoveDentry did not find the asked-for= dentry\n"));=0D + ASSERT (IsNodeInList (&ToBeRemoved->ListNode, &Parent->Children));=0D + RemoveEntryList (&ToBeRemoved->ListNode);=0D }=0D =0D /**=0D diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c b/Features/Ext4Pkg/Ext4Dxe/= Ext4Dxe.c index 43b9340d3956..2a4f5a7bd0ef 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c @@ -260,10 +260,12 @@ Ext4Stop ( =0D EFI_DRIVER_BINDING_PROTOCOL gExt4BindingProtocol =3D=0D {=0D - Ext4IsBindingSupported,=0D - Ext4Bind,=0D - Ext4Stop,=0D - EXT4_DRIVER_VERSION=0D + .Supported =3D Ext4IsBindingSupported,=0D + .Start =3D Ext4Bind,=0D + .Stop =3D Ext4Stop,=0D + .Version =3D EXT4_DRIVER_VERSION,=0D + .ImageHandle =3D NULL,=0D + .DriverBindingHandle =3D NULL=0D };=0D =0D /**=0D diff --git a/Features/Ext4Pkg/Ext4Dxe/Extents.c b/Features/Ext4Pkg/Ext4Dxe/= Extents.c index c3874df71751..d9ff69f21c14 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Extents.c +++ b/Features/Ext4Pkg/Ext4Dxe/Extents.c @@ -259,7 +259,8 @@ Ext4GetExtent ( =0D if (!(Inode->i_flags & EXT4_EXTENTS_FL)) {=0D // If this is an older ext2/ext3 filesystem, emulate Ext4GetExtent usi= ng the block map=0D - Status =3D Ext4GetBlocks (Partition, File, LogicalBlock, Extent);=0D + // We cast LogicalBlock to UINT32, considering ext2/3 are 32-bit=0D + Status =3D Ext4GetBlocks (Partition, File, (UINT32)LogicalBlock, Exten= t);=0D =0D if (!EFI_ERROR (Status)) {=0D Ext4CacheExtents (File, Extent, 1);=0D @@ -420,7 +421,7 @@ Ext4ExtentsMapKeyCompare ( Extent =3D UserStruct;=0D Block =3D (UINT32)(UINTN)StandaloneKey;=0D =0D - if ((Block >=3D Extent->ee_block) && (Block < Extent->ee_block + Ext4Get= ExtentLength (Extent))) {=0D + if ((Block >=3D Extent->ee_block) && (Block - Extent->ee_block < Ext4Get= ExtentLength (Extent))) {=0D return 0;=0D }=0D =0D diff --git a/Features/Ext4Pkg/Ext4Dxe/Inode.c b/Features/Ext4Pkg/Ext4Dxe/In= ode.c index 831f5946e870..4860cf576377 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Inode.c +++ b/Features/Ext4Pkg/Ext4Dxe/Inode.c @@ -100,7 +100,7 @@ Ext4Read ( EFI_STATUS Status;=0D BOOLEAN HasBackingExtent;=0D UINT32 HoleOff;=0D - UINTN HoleLen;=0D + UINT64 HoleLen;=0D UINT64 ExtentStartBytes;=0D UINT64 ExtentLengthBytes;=0D UINT64 ExtentLogicalBytes;=0D @@ -155,10 +155,10 @@ Ext4Read ( HoleLen =3D (Ext4GetExtentLength (&Extent) * Partition->BlockSize)= - HoleOff;=0D }=0D =0D - WasRead =3D HoleLen > RemainingRead ? RemainingRead : HoleLen;=0D + WasRead =3D HoleLen > RemainingRead ? RemainingRead : (UINTN)HoleLen= ;=0D // Potential improvement: In the future, we could get the file hole'= s total=0D // size and memset all that=0D - SetMem (Buffer, WasRead, 0);=0D + ZeroMem (Buffer, WasRead);=0D } else {=0D ExtentStartBytes =3D MultU64x32 (=0D LShiftU64 (Extent.ee_start_hi, 32) |=0D @@ -431,7 +431,7 @@ Ext4FileCreateTime ( Inode =3D File->Inode;=0D =0D if (!EXT4_INODE_HAS_FIELD (Inode, i_crtime)) {=0D - SetMem (Time, sizeof (EFI_TIME), 0);=0D + ZeroMem (Time, sizeof (EFI_TIME));=0D return;=0D }=0D =0D diff --git a/Features/Ext4Pkg/Ext4Dxe/Superblock.c b/Features/Ext4Pkg/Ext4D= xe/Superblock.c index 47fc3a65507a..a57728a9abe6 100644 --- a/Features/Ext4Pkg/Ext4Dxe/Superblock.c +++ b/Features/Ext4Pkg/Ext4Dxe/Superblock.c @@ -257,16 +257,17 @@ Ext4OpenSuperblock ( ));=0D =0D if (EXT4_IS_64_BIT (Partition)) {=0D + // s_desc_size should be 4 byte aligned and=0D + // 64 bit filesystems need DescSize to be 64 bytes=0D + if (((Sb->s_desc_size % 4) !=3D 0) || (Sb->s_desc_size < EXT4_64BIT_BL= OCK_DESC_SIZE)) {=0D + return EFI_VOLUME_CORRUPTED;=0D + }=0D +=0D Partition->DescSize =3D Sb->s_desc_size;=0D } else {=0D Partition->DescSize =3D EXT4_OLD_BLOCK_DESC_SIZE;=0D }=0D =0D - if ((Partition->DescSize < EXT4_64BIT_BLOCK_DESC_SIZE) && EXT4_IS_64_BIT= (Partition)) {=0D - // 64 bit filesystems need DescSize to be 64 bytes=0D - return EFI_VOLUME_CORRUPTED;=0D - }=0D -=0D if (!Ext4VerifySuperblockChecksum (Partition, Sb)) {=0D DEBUG ((DEBUG_ERROR, "[ext4] Bad superblock checksum %lx\n", Ext4Calcu= lateSuperblockChecksum (Partition, Sb)));=0D return EFI_VOLUME_CORRUPTED;=0D @@ -342,7 +343,7 @@ Ext4CalculateChecksum ( // For some reason, EXT4 really likes non-inverted CRC32C checksums,= so we stick to that here.=0D return ~CalculateCrc32c(Buffer, Length, ~InitialValue);=0D default:=0D - UNREACHABLE ();=0D + ASSERT (FALSE);=0D return 0;=0D }=0D }=0D --=20 2.37.0