public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements
@ 2023-01-11 23:59 Pedro Falcato
  2023-01-11 23:59 ` [PATCH 1/2] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Pedro Falcato @ 2023-01-11 23:59 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Marvin Häuser, Savva Mitrofanov

This patch set includes small fixes on Ext4Dxe, including a fix for a (mostly-harmless) out-of-bounds.
Previous versions of these patches were posted standalone before and are now being consolidated into a
patch-set for easier reviewing.

Cc: Marvin Häuser <mhaeuser@posteo.de>
Cc: Savva Mitrofanov <savvamtr@gmail.com>

Pedro Falcato (3):
  Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir
  Ext4Pkg: Add documentation surrounding ext4 directory entries
  Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries

 Features/Ext4Pkg/Ext4Dxe/Directory.c | 49 +++++++++++++++++++++-------
 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h  | 21 ++++++++++--
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h   | 13 ++++----
 3 files changed, 62 insertions(+), 21 deletions(-)

-- 
2.39.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/2] Ext4Pkg: Add documentation surrounding ext4 directory entries
  2023-01-11 23:59 [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements Pedro Falcato
@ 2023-01-11 23:59 ` Pedro Falcato
  2023-01-11 23:59 ` [PATCH 1/3] Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir Pedro Falcato
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Pedro Falcato @ 2023-01-11 23:59 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Marvin Häuser

Several questions have popped up regarding the ext4 directory entry
layout and contents off-list. Attempt to clarify these issues by adding
some explanatory comments.

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Marvin Häuser <mhaeuser@posteo.de>
---
 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 21 +++++++++++++++++++--
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h  |  5 ++---
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
index 4fd91a423324..d0a455d0e572 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
@@ -1,7 +1,7 @@
 /** @file
   Raw filesystem data structures
 
-  Copyright (c) 2021 Pedro Falcato All rights reserved.
+  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
   Layout of an EXT2/3/4 filesystem:
@@ -397,12 +397,29 @@ typedef struct _Ext4Inode {
   UINT32       i_projid;
 } EXT4_INODE;
 
+#define EXT4_NAME_MAX  255
+
 typedef struct {
+  // offset 0x0: inode number (if 0, unused entry, should skip.)
   UINT32    inode;
+  // offset 0x4: Directory entry's length.
+  //             Note: rec_len >= name_len + EXT4_MIN_DIR_ENTRY_LEN and rec_len % 4 == 0.
   UINT16    rec_len;
+  // offset 0x6: Directory entry's name's length
   UINT8     name_len;
+  // offset 0x7: Directory entry's file type indicator
   UINT8     file_type;
-  CHAR8     name[255];
+  // offset 0x8: name[name_len]: Variable length character array; not null-terminated.
+  CHAR8     name[EXT4_NAME_MAX];
+  // Further notes on names:
+  // 1) We use EXT4_NAME_MAX here instead of flexible arrays for ease of use around the driver.
+  //
+  // 2) ext4 directories are defined, as the documentation puts it, as:
+  // "a directory is more or less a flat file that maps an arbitrary byte string
+  // (usually ASCII) to an inode number on the filesystem". So, they are not
+  // necessarily encoded with ASCII, UTF-8, or any of the sort. We must treat it
+  // as a bag of bytes. When interacting with EFI interfaces themselves (which expect UCS-2)
+  // we skip any directory entry that is not valid UTF-8.
 } EXT4_DIR_ENTRY;
 
 #define EXT4_MIN_DIR_ENTRY_LEN  8
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
index adf3c13f6ea9..466e49523030 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -1,7 +1,7 @@
 /** @file
   Common header for the driver
 
-  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
 **/
 
@@ -31,8 +31,7 @@
 
 #include "Ext4Disk.h"
 
-#define SYMLOOP_MAX    8
-#define EXT4_NAME_MAX  255
+#define SYMLOOP_MAX  8
 //
 // We need to specify path length limit for security purposes, to prevent possible
 // overflows and dead-loop conditions. Originally this limit is absent in FS design,
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 1/3] Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir
  2023-01-11 23:59 [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements Pedro Falcato
  2023-01-11 23:59 ` [PATCH 1/2] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
@ 2023-01-11 23:59 ` Pedro Falcato
  2023-01-14 17:05   ` Marvin Häuser
  2023-01-11 23:59 ` [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Pedro Falcato @ 2023-01-11 23:59 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Savva Mitrofanov, Marvin Häuser

Fix an out-of-bounds read inside CompareMem() when
checking for "." or ".." by explicitly bounding name_len
to [0, 2] beforehand.

Reported-by: Savva Mitrofanov <savvamtr@gmail.com>
Fixes: 45e37d8533ca8 ("Ext4Pkg: Hide "." and ".." entries from Read() callers.")
Cc: Marvin Häuser <mhaeuser@posteo.de>
Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
---
 Features/Ext4Pkg/Ext4Dxe/Directory.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dxe/Directory.c
index 4441e6d192b6..6ed664fc632f 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Directory.c
+++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c
@@ -491,12 +491,14 @@ Ext4ReadDir (
     // or a checksum at the end of the directory block.
     // memcmp (and CompareMem) return 0 when the passed length is 0.
 
-    IsDotOrDotDot = Entry.name_len != 0 &&
-                    (CompareMem (Entry.name, ".", Entry.name_len) == 0 ||
-                     CompareMem (Entry.name, "..", Entry.name_len) == 0);
+    // We must bound name_len as > 0 and <= 2 to avoid any out-of-bounds accesses or bad detection of
+    // "." and "..".
+    IsDotOrDotDot = Entry.name_len > 0 && Entry.name_len <= 2 &&
+                    CompareMem (Entry.name, "..", Entry.name_len) == 0;
 
-    // When inode = 0, it's unused.
-    ShouldSkip = Entry.inode == 0 || IsDotOrDotDot;
+    // When inode = 0, it's unused. When name_len == 0, it's a nameless entry
+    // (which we should not expose to ReadDir).
+    ShouldSkip = Entry.inode == 0 || Entry.name_len == 0 || IsDotOrDotDot;
 
     if (ShouldSkip) {
       Offset += Entry.rec_len;
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries
  2023-01-11 23:59 [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements Pedro Falcato
  2023-01-11 23:59 ` [PATCH 1/2] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
  2023-01-11 23:59 ` [PATCH 1/3] Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir Pedro Falcato
@ 2023-01-11 23:59 ` Pedro Falcato
  2023-01-14 17:10   ` Marvin Häuser
  2023-01-11 23:59 ` [PATCH 2/2] Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries Pedro Falcato
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Pedro Falcato @ 2023-01-11 23:59 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Marvin Häuser

Several questions have popped up regarding the ext4 directory entry
layout and contents off-list. Attempt to clarify these issues by adding
some explanatory comments.

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Marvin Häuser <mhaeuser@posteo.de>
---
 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 21 +++++++++++++++++++--
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h  |  5 ++---
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
index 4fd91a423324..d0a455d0e572 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
@@ -1,7 +1,7 @@
 /** @file
   Raw filesystem data structures
 
-  Copyright (c) 2021 Pedro Falcato All rights reserved.
+  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
   Layout of an EXT2/3/4 filesystem:
@@ -397,12 +397,29 @@ typedef struct _Ext4Inode {
   UINT32       i_projid;
 } EXT4_INODE;
 
+#define EXT4_NAME_MAX  255
+
 typedef struct {
+  // offset 0x0: inode number (if 0, unused entry, should skip.)
   UINT32    inode;
+  // offset 0x4: Directory entry's length.
+  //             Note: rec_len >= name_len + EXT4_MIN_DIR_ENTRY_LEN and rec_len % 4 == 0.
   UINT16    rec_len;
+  // offset 0x6: Directory entry's name's length
   UINT8     name_len;
+  // offset 0x7: Directory entry's file type indicator
   UINT8     file_type;
-  CHAR8     name[255];
+  // offset 0x8: name[name_len]: Variable length character array; not null-terminated.
+  CHAR8     name[EXT4_NAME_MAX];
+  // Further notes on names:
+  // 1) We use EXT4_NAME_MAX here instead of flexible arrays for ease of use around the driver.
+  //
+  // 2) ext4 directories are defined, as the documentation puts it, as:
+  // "a directory is more or less a flat file that maps an arbitrary byte string
+  // (usually ASCII) to an inode number on the filesystem". So, they are not
+  // necessarily encoded with ASCII, UTF-8, or any of the sort. We must treat it
+  // as a bag of bytes. When interacting with EFI interfaces themselves (which expect UCS-2)
+  // we skip any directory entry that is not valid UTF-8.
 } EXT4_DIR_ENTRY;
 
 #define EXT4_MIN_DIR_ENTRY_LEN  8
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
index adf3c13f6ea9..466e49523030 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -1,7 +1,7 @@
 /** @file
   Common header for the driver
 
-  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
 **/
 
@@ -31,8 +31,7 @@
 
 #include "Ext4Disk.h"
 
-#define SYMLOOP_MAX    8
-#define EXT4_NAME_MAX  255
+#define SYMLOOP_MAX  8
 //
 // We need to specify path length limit for security purposes, to prevent possible
 // overflows and dead-loop conditions. Originally this limit is absent in FS design,
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries
  2023-01-11 23:59 [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements Pedro Falcato
                   ` (2 preceding siblings ...)
  2023-01-11 23:59 ` [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
@ 2023-01-11 23:59 ` Pedro Falcato
  2023-01-11 23:59 ` [PATCH 3/3] " Pedro Falcato
       [not found] ` <1739669F06B92E95.23170@groups.io>
  5 siblings, 0 replies; 10+ messages in thread
From: Pedro Falcato @ 2023-01-11 23:59 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Marvin Häuser

Previously, the handling was mixed and/or non-existent regarding non utf-8
dirent names. Clarify it.

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Marvin Häuser <mhaeuser@posteo.de>
---
 Features/Ext4Pkg/Ext4Dxe/Directory.c | 37 ++++++++++++++++++++++------
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h   |  8 +++---
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dxe/Directory.c
index 6ed664fc632f..ba781bad968c 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Directory.c
+++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c
@@ -1,7 +1,7 @@
 /** @file
   Directory related routines
 
-  Copyright (c) 2021 Pedro Falcato All rights reserved.
+  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -16,8 +16,9 @@
    @param[in]      Entry   Pointer to a EXT4_DIR_ENTRY.
    @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
 
-   @retval EFI_SUCCESS   The filename was succesfully retrieved and converted to UCS2.
-   @retval !EFI_SUCCESS  Failure.
+   @retval EFI_SUCCESS              The filename was succesfully retrieved and converted to UCS2.
+   @retval EFI_INVALID_PARAMETER    The filename is not valid UTF-8.
+   @retval !EFI_SUCCESS             Failure.
 **/
 EFI_STATUS
 Ext4GetUcs2DirentName (
@@ -174,10 +175,16 @@ Ext4RetrieveDirent (
        * need to form valid ASCII/UTF-8 sequences.
        */
       if (EFI_ERROR (Status)) {
-        // If we error out, skip this entry
-        // I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
-        BlockOffset += Entry->rec_len;
-        continue;
+        if (Status == EFI_INVALID_PARAMETER) {
+          // If we error out due to a bad UTF-8 sequence (see Ext4GetUcs2DirentName), skip this entry.
+          // I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
+          BlockOffset += Entry->rec_len;
+          continue;
+        }
+
+        // Other sorts of errors should just error out.
+        FreePool (Buf);
+        return Status;
       }
 
       if ((Entry->name_len == StrLen (Name)) &&
@@ -436,6 +443,7 @@ Ext4ReadDir (
   EXT4_FILE       *TempFile;
   BOOLEAN         ShouldSkip;
   BOOLEAN         IsDotOrDotDot;
+  CHAR16          DirentUcs2Name[EXT4_NAME_MAX + 1];
 
   DirIno     = File->Inode;
   Status     = EFI_SUCCESS;
@@ -505,6 +513,21 @@ Ext4ReadDir (
       continue;
     }
 
+    // Test if the dirent is valid utf-8. This is already done inside Ext4OpenDirent but EFI_INVALID_PARAMETER
+    // has the danger of its meaning being overloaded in many places, so we can't skip according to that.
+    // So test outside of it, explicitly.
+    Status = Ext4GetUcs2DirentName (&Entry, DirentUcs2Name);
+
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_INVALID_PARAMETER) {
+        // Bad UTF-8, skip.
+        Offset += Entry.rec_len;
+        continue;
+      }
+
+      goto Out;
+    }
+
     Status = Ext4OpenDirent (Partition, EFI_FILE_MODE_READ, &TempFile, &Entry, File);
 
     if (EFI_ERROR (Status)) {
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
index 466e49523030..41779dad855f 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -944,11 +944,11 @@ Ext4StrCmpInsensitive (
    Retrieves the filename of the directory entry and converts it to UTF-16/UCS-2
 
    @param[in]      Entry   Pointer to a EXT4_DIR_ENTRY.
-   @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size
-EXT4_NAME_MAX + 1.
+   @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
 
-   @retval EFI_SUCCESS   Unicode collation was successfully initialised.
-   @retval !EFI_SUCCESS  Failure.
+   @retval EFI_SUCCESS              The filename was succesfully retrieved and converted to UCS2.
+   @retval EFI_INVALID_PARAMETER    The filename is not valid UTF-8.
+   @retval !EFI_SUCCESS             Failure.
 **/
 EFI_STATUS
 Ext4GetUcs2DirentName (
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries
  2023-01-11 23:59 [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements Pedro Falcato
                   ` (3 preceding siblings ...)
  2023-01-11 23:59 ` [PATCH 2/2] Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries Pedro Falcato
@ 2023-01-11 23:59 ` Pedro Falcato
  2023-01-14 17:13   ` Marvin Häuser
       [not found] ` <1739669F06B92E95.23170@groups.io>
  5 siblings, 1 reply; 10+ messages in thread
From: Pedro Falcato @ 2023-01-11 23:59 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Marvin Häuser

Previously, the handling was mixed and/or non-existent regarding non utf-8
dirent names. Clarify it.

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Marvin Häuser <mhaeuser@posteo.de>
---
 Features/Ext4Pkg/Ext4Dxe/Directory.c | 37 ++++++++++++++++++++++------
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h   |  8 +++---
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dxe/Directory.c
index 6ed664fc632f..ba781bad968c 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Directory.c
+++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c
@@ -1,7 +1,7 @@
 /** @file
   Directory related routines
 
-  Copyright (c) 2021 Pedro Falcato All rights reserved.
+  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -16,8 +16,9 @@
    @param[in]      Entry   Pointer to a EXT4_DIR_ENTRY.
    @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
 
-   @retval EFI_SUCCESS   The filename was succesfully retrieved and converted to UCS2.
-   @retval !EFI_SUCCESS  Failure.
+   @retval EFI_SUCCESS              The filename was succesfully retrieved and converted to UCS2.
+   @retval EFI_INVALID_PARAMETER    The filename is not valid UTF-8.
+   @retval !EFI_SUCCESS             Failure.
 **/
 EFI_STATUS
 Ext4GetUcs2DirentName (
@@ -174,10 +175,16 @@ Ext4RetrieveDirent (
        * need to form valid ASCII/UTF-8 sequences.
        */
       if (EFI_ERROR (Status)) {
-        // If we error out, skip this entry
-        // I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
-        BlockOffset += Entry->rec_len;
-        continue;
+        if (Status == EFI_INVALID_PARAMETER) {
+          // If we error out due to a bad UTF-8 sequence (see Ext4GetUcs2DirentName), skip this entry.
+          // I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
+          BlockOffset += Entry->rec_len;
+          continue;
+        }
+
+        // Other sorts of errors should just error out.
+        FreePool (Buf);
+        return Status;
       }
 
       if ((Entry->name_len == StrLen (Name)) &&
@@ -436,6 +443,7 @@ Ext4ReadDir (
   EXT4_FILE       *TempFile;
   BOOLEAN         ShouldSkip;
   BOOLEAN         IsDotOrDotDot;
+  CHAR16          DirentUcs2Name[EXT4_NAME_MAX + 1];
 
   DirIno     = File->Inode;
   Status     = EFI_SUCCESS;
@@ -505,6 +513,21 @@ Ext4ReadDir (
       continue;
     }
 
+    // Test if the dirent is valid utf-8. This is already done inside Ext4OpenDirent but EFI_INVALID_PARAMETER
+    // has the danger of its meaning being overloaded in many places, so we can't skip according to that.
+    // So test outside of it, explicitly.
+    Status = Ext4GetUcs2DirentName (&Entry, DirentUcs2Name);
+
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_INVALID_PARAMETER) {
+        // Bad UTF-8, skip.
+        Offset += Entry.rec_len;
+        continue;
+      }
+
+      goto Out;
+    }
+
     Status = Ext4OpenDirent (Partition, EFI_FILE_MODE_READ, &TempFile, &Entry, File);
 
     if (EFI_ERROR (Status)) {
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
index 466e49523030..41779dad855f 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -944,11 +944,11 @@ Ext4StrCmpInsensitive (
    Retrieves the filename of the directory entry and converts it to UTF-16/UCS-2
 
    @param[in]      Entry   Pointer to a EXT4_DIR_ENTRY.
-   @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size
-EXT4_NAME_MAX + 1.
+   @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
 
-   @retval EFI_SUCCESS   Unicode collation was successfully initialised.
-   @retval !EFI_SUCCESS  Failure.
+   @retval EFI_SUCCESS              The filename was succesfully retrieved and converted to UCS2.
+   @retval EFI_INVALID_PARAMETER    The filename is not valid UTF-8.
+   @retval !EFI_SUCCESS             Failure.
 **/
 EFI_STATUS
 Ext4GetUcs2DirentName (
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [edk2-devel] [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries
       [not found] ` <1739669F06B92E95.23170@groups.io>
@ 2023-01-12  0:04   ` Pedro Falcato
  0 siblings, 0 replies; 10+ messages in thread
From: Pedro Falcato @ 2023-01-12  0:04 UTC (permalink / raw)
  To: devel, pedro.falcato; +Cc: Marvin Häuser

[-- Attachment #1: Type: text/plain, Size: 3575 bytes --]

Apologies for the duplicate send of these patches, small mistake using git
send-email *.patch ;)
Please only consider the patches that start with [PATCH N/3].

On Wed, Jan 11, 2023 at 11:59 PM Pedro Falcato via groups.io <pedro.falcato=
gmail.com@groups.io> wrote:

> Several questions have popped up regarding the ext4 directory entry
> layout and contents off-list. Attempt to clarify these issues by adding
> some explanatory comments.
>
> Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
> Cc: Marvin Häuser <mhaeuser@posteo.de>
> ---
>  Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 21 +++++++++++++++++++--
>  Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h  |  5 ++---
>  2 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> index 4fd91a423324..d0a455d0e572 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> @@ -1,7 +1,7 @@
>  /** @file
>    Raw filesystem data structures
>
> -  Copyright (c) 2021 Pedro Falcato All rights reserved.
> +  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
>    Layout of an EXT2/3/4 filesystem:
> @@ -397,12 +397,29 @@ typedef struct _Ext4Inode {
>    UINT32       i_projid;
>  } EXT4_INODE;
>
> +#define EXT4_NAME_MAX  255
> +
>  typedef struct {
> +  // offset 0x0: inode number (if 0, unused entry, should skip.)
>    UINT32    inode;
> +  // offset 0x4: Directory entry's length.
> +  //             Note: rec_len >= name_len + EXT4_MIN_DIR_ENTRY_LEN and
> rec_len % 4 == 0.
>    UINT16    rec_len;
> +  // offset 0x6: Directory entry's name's length
>    UINT8     name_len;
> +  // offset 0x7: Directory entry's file type indicator
>    UINT8     file_type;
> -  CHAR8     name[255];
> +  // offset 0x8: name[name_len]: Variable length character array; not
> null-terminated.
> +  CHAR8     name[EXT4_NAME_MAX];
> +  // Further notes on names:
> +  // 1) We use EXT4_NAME_MAX here instead of flexible arrays for ease of
> use around the driver.
> +  //
> +  // 2) ext4 directories are defined, as the documentation puts it, as:
> +  // "a directory is more or less a flat file that maps an arbitrary byte
> string
> +  // (usually ASCII) to an inode number on the filesystem". So, they are
> not
> +  // necessarily encoded with ASCII, UTF-8, or any of the sort. We must
> treat it
> +  // as a bag of bytes. When interacting with EFI interfaces themselves
> (which expect UCS-2)
> +  // we skip any directory entry that is not valid UTF-8.
>  } EXT4_DIR_ENTRY;
>
>  #define EXT4_MIN_DIR_ENTRY_LEN  8
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> index adf3c13f6ea9..466e49523030 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> @@ -1,7 +1,7 @@
>  /** @file
>    Common header for the driver
>
> -  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
>  **/
>
> @@ -31,8 +31,7 @@
>
>  #include "Ext4Disk.h"
>
> -#define SYMLOOP_MAX    8
> -#define EXT4_NAME_MAX  255
> +#define SYMLOOP_MAX  8
>  //
>  // We need to specify path length limit for security purposes, to prevent
> possible
>  // overflows and dead-loop conditions. Originally this limit is absent in
> FS design,
> --
> 2.39.0
>
>
>
> 
>
>
>

-- 
Pedro

[-- Attachment #2: Type: text/html, Size: 4400 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir
  2023-01-11 23:59 ` [PATCH 1/3] Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir Pedro Falcato
@ 2023-01-14 17:05   ` Marvin Häuser
  0 siblings, 0 replies; 10+ messages in thread
From: Marvin Häuser @ 2023-01-14 17:05 UTC (permalink / raw)
  To: Pedro Falcato; +Cc: edk2-devel-groups-io, Savva Mitrofanov

[-- Attachment #1: Type: text/plain, Size: 2060 bytes --]

Reviewed-by: Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>>

(Still two comments for next time)

> On 12. Jan 2023, at 00:59, Pedro Falcato <pedro.falcato@gmail.com> wrote:
> 
> Fix an out-of-bounds read inside CompareMem() when
> checking for "." or ".." by explicitly bounding name_len
> to [0, 2] beforehand.
> 
> Reported-by: Savva Mitrofanov <savvamtr@gmail.com>
> Fixes: 45e37d8533ca8 ("Ext4Pkg: Hide "." and ".." entries from Read() callers.")
> Cc: Marvin Häuser <mhaeuser@posteo.de>
> Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
> ---
> Features/Ext4Pkg/Ext4Dxe/Directory.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dxe/Directory.c
> index 4441e6d192b6..6ed664fc632f 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Directory.c
> +++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c
> @@ -491,12 +491,14 @@ Ext4ReadDir (
>     // or a checksum at the end of the directory block.
>     // memcmp (and CompareMem) return 0 when the passed length is 0.
> 
> -    IsDotOrDotDot = Entry.name_len != 0 &&
> -                    (CompareMem (Entry.name, ".", Entry.name_len) == 0 ||
> -                     CompareMem (Entry.name, "..", Entry.name_len) == 0);
> +    // We must bound name_len as > 0 and <= 2 to avoid any out-of-bounds accesses or bad detection of

"bad detection" = false positive?

> +    // "." and "..".
> +    IsDotOrDotDot = Entry.name_len > 0 && Entry.name_len <= 2 &&
> +                    CompareMem (Entry.name, "..", Entry.name_len) == 0;
> 
> -    // When inode = 0, it's unused.
> -    ShouldSkip = Entry.inode == 0 || IsDotOrDotDot;
> +    // When inode = 0, it's unused. When name_len == 0, it's a nameless entry

Inconsistency between "=" and "==".

> +    // (which we should not expose to ReadDir).
> +    ShouldSkip = Entry.inode == 0 || Entry.name_len == 0 || IsDotOrDotDot;
> 
>     if (ShouldSkip) {
>       Offset += Entry.rec_len;
> -- 
> 2.39.0
> 


[-- Attachment #2: Type: text/html, Size: 3162 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries
  2023-01-11 23:59 ` [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
@ 2023-01-14 17:10   ` Marvin Häuser
  0 siblings, 0 replies; 10+ messages in thread
From: Marvin Häuser @ 2023-01-14 17:10 UTC (permalink / raw)
  To: Pedro Falcato; +Cc: edk2-devel-groups-io

[-- Attachment #1: Type: text/plain, Size: 3589 bytes --]

Well, this is still not Doxygen-friendly (requires three slashes) and it's still awkward (as in done nowhere else) to explicitly list the offset or name in the comment. In case neither is a concern:

Reviewed-by: Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>>

> On 12. Jan 2023, at 00:59, Pedro Falcato <pedro.falcato@gmail.com> wrote:
> 
> Several questions have popped up regarding the ext4 directory entry
> layout and contents off-list. Attempt to clarify these issues by adding
> some explanatory comments.
> 
> Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
> Cc: Marvin Häuser <mhaeuser@posteo.de>
> ---
> Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 21 +++++++++++++++++++--
> Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h  |  5 ++---
> 2 files changed, 21 insertions(+), 5 deletions(-)
> 
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> index 4fd91a423324..d0a455d0e572 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
> @@ -1,7 +1,7 @@
> /** @file
>   Raw filesystem data structures
> 
> -  Copyright (c) 2021 Pedro Falcato All rights reserved.
> +  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
>   SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>   Layout of an EXT2/3/4 filesystem:
> @@ -397,12 +397,29 @@ typedef struct _Ext4Inode {
>   UINT32       i_projid;
> } EXT4_INODE;
> 
> +#define EXT4_NAME_MAX  255
> +
> typedef struct {
> +  // offset 0x0: inode number (if 0, unused entry, should skip.)
>   UINT32    inode;
> +  // offset 0x4: Directory entry's length.
> +  //             Note: rec_len >= name_len + EXT4_MIN_DIR_ENTRY_LEN and rec_len % 4 == 0.
>   UINT16    rec_len;
> +  // offset 0x6: Directory entry's name's length
>   UINT8     name_len;
> +  // offset 0x7: Directory entry's file type indicator
>   UINT8     file_type;
> -  CHAR8     name[255];
> +  // offset 0x8: name[name_len]: Variable length character array; not null-terminated.
> +  CHAR8     name[EXT4_NAME_MAX];
> +  // Further notes on names:
> +  // 1) We use EXT4_NAME_MAX here instead of flexible arrays for ease of use around the driver.
> +  //
> +  // 2) ext4 directories are defined, as the documentation puts it, as:
> +  // "a directory is more or less a flat file that maps an arbitrary byte string
> +  // (usually ASCII) to an inode number on the filesystem". So, they are not
> +  // necessarily encoded with ASCII, UTF-8, or any of the sort. We must treat it
> +  // as a bag of bytes. When interacting with EFI interfaces themselves (which expect UCS-2)
> +  // we skip any directory entry that is not valid UTF-8.
> } EXT4_DIR_ENTRY;
> 
> #define EXT4_MIN_DIR_ENTRY_LEN  8
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> index adf3c13f6ea9..466e49523030 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> @@ -1,7 +1,7 @@
> /** @file
>   Common header for the driver
> 
> -  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
> **/
> 
> @@ -31,8 +31,7 @@
> 
> #include "Ext4Disk.h"
> 
> -#define SYMLOOP_MAX    8
> -#define EXT4_NAME_MAX  255
> +#define SYMLOOP_MAX  8
> //
> // We need to specify path length limit for security purposes, to prevent possible
> // overflows and dead-loop conditions. Originally this limit is absent in FS design,
> -- 
> 2.39.0
> 


[-- Attachment #2: Type: text/html, Size: 4439 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries
  2023-01-11 23:59 ` [PATCH 3/3] " Pedro Falcato
@ 2023-01-14 17:13   ` Marvin Häuser
  0 siblings, 0 replies; 10+ messages in thread
From: Marvin Häuser @ 2023-01-14 17:13 UTC (permalink / raw)
  To: Pedro Falcato; +Cc: devel

[-- Attachment #1: Type: text/plain, Size: 4579 bytes --]

Reviewed-by: Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>>

> On 12. Jan 2023, at 00:59, Pedro Falcato <pedro.falcato@gmail.com> wrote:
> 
> Previously, the handling was mixed and/or non-existent regarding non utf-8
> dirent names. Clarify it.
> 
> Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
> Cc: Marvin Häuser <mhaeuser@posteo.de>
> ---
> Features/Ext4Pkg/Ext4Dxe/Directory.c | 37 ++++++++++++++++++++++------
> Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h   |  8 +++---
> 2 files changed, 34 insertions(+), 11 deletions(-)
> 
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dxe/Directory.c
> index 6ed664fc632f..ba781bad968c 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Directory.c
> +++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c
> @@ -1,7 +1,7 @@
> /** @file
>   Directory related routines
> 
> -  Copyright (c) 2021 Pedro Falcato All rights reserved.
> +  Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
> 
>   SPDX-License-Identifier: BSD-2-Clause-Patent
> **/
> @@ -16,8 +16,9 @@
>    @param[in]      Entry   Pointer to a EXT4_DIR_ENTRY.
>    @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
> 
> -   @retval EFI_SUCCESS   The filename was succesfully retrieved and converted to UCS2.
> -   @retval !EFI_SUCCESS  Failure.
> +   @retval EFI_SUCCESS              The filename was succesfully retrieved and converted to UCS2.
> +   @retval EFI_INVALID_PARAMETER    The filename is not valid UTF-8.
> +   @retval !EFI_SUCCESS             Failure.
> **/
> EFI_STATUS
> Ext4GetUcs2DirentName (
> @@ -174,10 +175,16 @@ Ext4RetrieveDirent (
>        * need to form valid ASCII/UTF-8 sequences.
>        */
>       if (EFI_ERROR (Status)) {
> -        // If we error out, skip this entry
> -        // I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
> -        BlockOffset += Entry->rec_len;
> -        continue;
> +        if (Status == EFI_INVALID_PARAMETER) {
> +          // If we error out due to a bad UTF-8 sequence (see Ext4GetUcs2DirentName), skip this entry.
> +          // I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
> +          BlockOffset += Entry->rec_len;
> +          continue;
> +        }
> +
> +        // Other sorts of errors should just error out.
> +        FreePool (Buf);
> +        return Status;
>       }
> 
>       if ((Entry->name_len == StrLen (Name)) &&
> @@ -436,6 +443,7 @@ Ext4ReadDir (
>   EXT4_FILE       *TempFile;
>   BOOLEAN         ShouldSkip;
>   BOOLEAN         IsDotOrDotDot;
> +  CHAR16          DirentUcs2Name[EXT4_NAME_MAX + 1];
> 
>   DirIno     = File->Inode;
>   Status     = EFI_SUCCESS;
> @@ -505,6 +513,21 @@ Ext4ReadDir (
>       continue;
>     }
> 
> +    // Test if the dirent is valid utf-8. This is already done inside Ext4OpenDirent but EFI_INVALID_PARAMETER
> +    // has the danger of its meaning being overloaded in many places, so we can't skip according to that.
> +    // So test outside of it, explicitly.
> +    Status = Ext4GetUcs2DirentName (&Entry, DirentUcs2Name);
> +
> +    if (EFI_ERROR (Status)) {
> +      if (Status == EFI_INVALID_PARAMETER) {
> +        // Bad UTF-8, skip.
> +        Offset += Entry.rec_len;
> +        continue;
> +      }
> +
> +      goto Out;
> +    }
> +
>     Status = Ext4OpenDirent (Partition, EFI_FILE_MODE_READ, &TempFile, &Entry, File);
> 
>     if (EFI_ERROR (Status)) {
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> index 466e49523030..41779dad855f 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> @@ -944,11 +944,11 @@ Ext4StrCmpInsensitive (
>    Retrieves the filename of the directory entry and converts it to UTF-16/UCS-2
> 
>    @param[in]      Entry   Pointer to a EXT4_DIR_ENTRY.
> -   @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size
> -EXT4_NAME_MAX + 1.
> +   @param[out]      Ucs2FileName   Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
> 
> -   @retval EFI_SUCCESS   Unicode collation was successfully initialised.
> -   @retval !EFI_SUCCESS  Failure.
> +   @retval EFI_SUCCESS              The filename was succesfully retrieved and converted to UCS2.
> +   @retval EFI_INVALID_PARAMETER    The filename is not valid UTF-8.
> +   @retval !EFI_SUCCESS             Failure.
> **/
> EFI_STATUS
> Ext4GetUcs2DirentName (
> -- 
> 2.39.0
> 


[-- Attachment #2: Type: text/html, Size: 6968 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-01-14 17:13 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-11 23:59 [PATCH 0/3] Ext4Pkg: Small ext4 fixes and improvements Pedro Falcato
2023-01-11 23:59 ` [PATCH 1/2] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
2023-01-11 23:59 ` [PATCH 1/3] Ext4Pkg: Fix out-of-bounds read in Ext4ReadDir Pedro Falcato
2023-01-14 17:05   ` Marvin Häuser
2023-01-11 23:59 ` [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato
2023-01-14 17:10   ` Marvin Häuser
2023-01-11 23:59 ` [PATCH 2/2] Ext4Pkg: Fix and clarify handling regarding non-utf8 dir entries Pedro Falcato
2023-01-11 23:59 ` [PATCH 3/3] " Pedro Falcato
2023-01-14 17:13   ` Marvin Häuser
     [not found] ` <1739669F06B92E95.23170@groups.io>
2023-01-12  0:04   ` [edk2-devel] [PATCH 2/3] Ext4Pkg: Add documentation surrounding ext4 directory entries Pedro Falcato

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox