public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platforms][PATCH v2 0/2] Ext4Pkg: Add Symbolic Links support
@ 2022-07-20  6:47 Savva Mitrofanov
  2022-07-20  6:47 ` [edk2-platforms][PATCH v2 1/2] Ext4Pkg: Add symbolic links support Savva Mitrofanov
  2022-07-20  6:47 ` [edk2-platforms][PATCH v2 2/2] Ext4Pkg: Add base containing record macro for EXT4_FILE Savva Mitrofanov
  0 siblings, 2 replies; 4+ messages in thread
From: Savva Mitrofanov @ 2022-07-20  6:47 UTC (permalink / raw)
  To: devel; +Cc: Marvin Häuser, Pedro Falcato, Vitaly Cheptsov

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3677

Hi all,

In previous patchset I forgot to mention 3677 bug dedicated to symlinks. 
So in v2 I took it into account.
This patchset adds symbolic links support with simple recursion protection based
on symbolic link nest level limitation, also I included patch which adds BASE_CR
to extract EXT4_FILE private structure to prevent possible code corruption caused
by structure changes and rearrangements in future.

REF: https://github.com/savvamitrofanov/edk2-platforms/tree/ext4pkg_symlink_support

Cc: Marvin Häuser <mhaeuser@posteo.de>
Cc: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>

Savva Mitrofanov (2):
  Ext4Pkg: Add symbolic links support
  Ext4Pkg: Add base containing record macro for EXT4_FILE

 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h |   2 +-
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h  | 101 +++++-
 Features/Ext4Pkg/Ext4Dxe/File.c     | 375 ++++++++++++++++++--
 Features/Ext4Pkg/Ext4Dxe/Inode.c    |  38 ++
 4 files changed, 477 insertions(+), 39 deletions(-)

-- 
2.37.0


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

* [edk2-platforms][PATCH v2 1/2] Ext4Pkg: Add symbolic links support
  2022-07-20  6:47 [edk2-platforms][PATCH v2 0/2] Ext4Pkg: Add Symbolic Links support Savva Mitrofanov
@ 2022-07-20  6:47 ` Savva Mitrofanov
  2022-07-20  6:47 ` [edk2-platforms][PATCH v2 2/2] Ext4Pkg: Add base containing record macro for EXT4_FILE Savva Mitrofanov
  1 sibling, 0 replies; 4+ messages in thread
From: Savva Mitrofanov @ 2022-07-20  6:47 UTC (permalink / raw)
  To: devel; +Cc: Marvin Häuser, Pedro Falcato, Vitaly Cheptsov

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3677

Provided support for symlink file type. Added routine which allows
reading and following them through recursive open() call. As a security
meausure implemented simple symlink loop check with nest level limit
equal 8. Also this patch moves Ext4Open functionality to internal
routine.

Cc: Marvin Häuser <mhaeuser@posteo.de>
Cc: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>
Signed-off-by: Savva Mitrofanov <savvamtr@gmail.com>
---
 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h |   2 +-
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h  |  99 +++++-
 Features/Ext4Pkg/Ext4Dxe/File.c     | 365 ++++++++++++++++++--
 Features/Ext4Pkg/Ext4Dxe/Inode.c    |  38 ++
 4 files changed, 470 insertions(+), 34 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
index a55cd2fa68ad..6f83dcf65429 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
@@ -171,7 +171,7 @@
 #define EXT4_DIRTY_FL         0x00000100
 #define EXT4_COMPRBLK_FL      0x00000200
 #define EXT4_NOCOMPR_FL       0x00000400
-#define EXT4_ECOMPR_FL        0x00000800
+#define EXT4_ENCRYPT_FL       0x00000800
 #define EXT4_BTREE_FL         0x00001000
 #define EXT4_INDEX_FL         0x00002000
 #define EXT4_JOURNAL_DATA_FL  0x00004000
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
index b1508482b0a7..a1eb32aa2cff 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -31,7 +31,10 @@
 
 #include "Ext4Disk.h"
 
-#define EXT4_NAME_MAX  255
+#define SYMLOOP_MAX             8
+#define EXT4_NAME_MAX           255
+#define EFI_PATH_MAX            4096
+#define EXT4_FAST_SYMLINK_SIZE  60
 
 #define EXT4_DRIVER_VERSION  0x0000
 
@@ -324,11 +327,11 @@ number of read bytes.
 **/
 EFI_STATUS
 Ext4Read (
-  IN EXT4_PARTITION  *Partition,
-  IN EXT4_FILE       *File,
-  OUT VOID           *Buffer,
-  IN UINT64          Offset,
-  IN OUT UINTN       *Length
+  IN     EXT4_PARTITION  *Partition,
+  IN     EXT4_FILE       *File,
+  OUT    VOID            *Buffer,
+  IN     UINT64          Offset,
+  IN OUT UINTN           *Length
   );
 
 /**
@@ -368,6 +371,7 @@ struct _Ext4File {
 
   UINT64                OpenMode;
   UINT64                Position;
+  UINT32                Symloops;
 
   EXT4_PARTITION        *Partition;
 
@@ -497,6 +501,45 @@ Ext4SetupFile (
   IN EXT4_PARTITION  *Partition
   );
 
+/**
+  Opens a new file relative to the source file's location.
+
+  @param[out] FoundFile  A pointer to the location to return the opened handle for the new
+                         file.
+  @param[in]  Source     A pointer to the EXT4_FILE instance that is the file
+                         handle to the source location. This would typically be an open
+                         handle to a directory.
+  @param[in]  FileName   The Null-terminated string of the name of the file to be opened.
+                         The file name may contain the following path modifiers: "\", ".",
+                         and "..".
+  @param[in]  OpenMode   The mode to open the file. The only valid combinations that the
+                         file may be opened with are: Read, Read/Write, or Create/Read/Write.
+  @param[in]  Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
+                         attribute bits for the newly created file.
+
+  @retval EFI_SUCCESS          The file was opened.
+  @retval EFI_NOT_FOUND        The specified file could not be found on the device.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
+                               longer supported.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  An attempt was made to create a file, or open a file for write
+                               when the media is write-protected.
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+EFI_STATUS
+Ext4OpenInternal (
+  OUT EXT4_FILE  **FoundFile,
+  IN  EXT4_FILE  *Source,
+  IN  CHAR16     *FileName,
+  IN  UINT64     OpenMode,
+  IN  UINT64     Attributes
+  );
+
 /**
    Closes a file.
 
@@ -774,6 +817,28 @@ Ext4FileIsDir (
   IN CONST EXT4_FILE  *File
   );
 
+/**
+   Checks if a file is a symlink.
+   @param[in]      File          Pointer to the opened file.
+
+   @return TRUE if file is a symlink.
+**/
+BOOLEAN
+Ext4FileIsSymlink (
+  IN CONST EXT4_FILE  *File
+  );
+
+/**
+   Detects if a symlink is a fast symlink.
+   @param[in]      File          Pointer to the opened file.
+
+   @return TRUE if file is a fast symlink.
+**/
+BOOLEAN
+Ext4SymlinkIsFastSymlink (
+  IN CONST EXT4_FILE  *File
+  );
+
 /**
    Checks if a file is a regular file.
    @param[in]      File          Pointer to the opened file.
@@ -797,7 +862,7 @@ Ext4FileIsReg (
            it's a regular file or a directory, since most other file types
            don't make sense under UEFI.
 **/
-#define Ext4FileIsOpenable(File)  (Ext4FileIsReg(File) || Ext4FileIsDir(File))
+#define Ext4FileIsOpenable(File)  (Ext4FileIsReg (File) || Ext4FileIsDir (File) || Ext4FileIsSymlink (File))
 
 #define EXT4_INODE_HAS_FIELD(Inode, Field)                                     \
   (Inode->i_extra_isize + EXT4_GOOD_OLD_INODE_SIZE >=                          \
@@ -935,6 +1000,26 @@ Ext4ReadDir (
   IN OUT UINTN       *OutLength
   );
 
+/**
+  Reads a symlink file.
+
+  @param[in]      Partition   Pointer to the ext4 partition.
+  @param[in]      File        Pointer to the open symlink file.
+  @param[out]     Symlink     Pointer to the output unicode symlink string.
+
+  @retval EFI_SUCCESS           Symlink was read.
+  @retval EFI_ACCESS_DENIED     Symlink is encrypted.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation error.
+  @retval EFI_INVALID_PARAMETER Symlink path has incorrect length
+  @retval EFI_VOLUME_CORRUPTED  Symlink read block size differ from inode value
+**/
+EFI_STATUS
+Ext4ReadSymlink (
+  IN     EXT4_PARTITION  *Partition,
+  IN     EXT4_FILE       *File,
+  OUT    CHAR16          **Symlink
+  );
+
 /**
    Initialises the (empty) extents map, that will work as a cache of extents.
 
diff --git a/Features/Ext4Pkg/Ext4Dxe/File.c b/Features/Ext4Pkg/Ext4Dxe/File.c
index ff1746d5640a..0fb9e05e6647 100644
--- a/Features/Ext4Pkg/Ext4Dxe/File.c
+++ b/Features/Ext4Pkg/Ext4Dxe/File.c
@@ -134,14 +134,230 @@ Ext4DirCanLookup (
   return (File->Inode->i_mode & EXT4_INO_PERM_EXEC_OWNER) == EXT4_INO_PERM_EXEC_OWNER;
 }
 
+/**
+  Reads a fast symlink file.
+
+  @param[in]      Partition   Pointer to the ext4 partition.
+  @param[in]      File        Pointer to the open symlink file.
+  @param[out]     AsciiSymlink     Pointer to the output ascii symlink string.
+  @param[out]     AsciiSymlinkSize Pointer to the output ascii symlink string length.
+
+  @retval EFI_SUCCESS           Fast symlink was read.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation error.
+**/
+STATIC
+EFI_STATUS
+Ext4ReadFastSymlink (
+  IN     EXT4_PARTITION  *Partition,
+  IN     EXT4_FILE       *File,
+  OUT    CHAR8           **AsciiSymlink,
+  OUT    UINT32          *AsciiSymlinkSize
+  )
+{
+  EFI_STATUS  Status;
+  CHAR8       *AsciiSymlinkTmp;
+
+  AsciiSymlinkTmp = AllocatePool (EXT4_FAST_SYMLINK_SIZE + 1);
+  if (AsciiSymlinkTmp == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink ascii string buffer\n"));
+    return Status;
+  }
+
+  CopyMem (AsciiSymlinkTmp, File->Inode->i_data, EXT4_FAST_SYMLINK_SIZE);
+
+  //
+  // Add null-terminator
+  //
+  AsciiSymlinkTmp[EXT4_FAST_SYMLINK_SIZE] = '\0';
+
+  *AsciiSymlink     = AsciiSymlinkTmp;
+  *AsciiSymlinkSize = EXT4_FAST_SYMLINK_SIZE + 1;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads a slow symlink file.
+
+  @param[in]      Partition        Pointer to the ext4 partition.
+  @param[in]      File             Pointer to the open symlink file.
+  @param[out]     AsciiSymlink     Pointer to the output ascii symlink string.
+  @param[out]     AsciiSymlinkSize Pointer to the output ascii symlink string length.
+
+  @retval EFI_SUCCESS           Slow symlink was read.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation error.
+  @retval EFI_INVALID_PARAMETER Slow symlink path has incorrect length
+  @retval EFI_VOLUME_CORRUPTED  Symlink read block size differ from inode value
+**/
+STATIC
+EFI_STATUS
+Ext4ReadSlowSymlink (
+  IN     EXT4_PARTITION  *Partition,
+  IN     EXT4_FILE       *File,
+  OUT    CHAR8           **AsciiSymlink,
+  OUT    UINT32          *AsciiSymlinkSize
+  )
+{
+  EFI_STATUS  Status;
+  CHAR8       *SymlinkTmp;
+  UINT64      SymlinkSizeTmp;
+  UINT32      SymlinkAllocateSize;
+  UINTN       ReadSize;
+
+  SymlinkSizeTmp = EXT4_INODE_SIZE (File->Inode);
+
+  //
+  // Allocate EXT4_INODE_SIZE + 1
+  //
+  if (SymlinkSizeTmp <= EFI_PATH_MAX - 1) {
+    SymlinkAllocateSize = (UINT32)SymlinkSizeTmp + 1;
+  } else {
+    DEBUG ((
+      DEBUG_FS,
+      "[ext4] Error! Symlink path maximum length was hit!\n"
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SymlinkTmp = AllocatePool (SymlinkAllocateSize);
+  if (SymlinkTmp == NULL) {
+    DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink ascii string buffer\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ReadSize = (UINTN)SymlinkSizeTmp;
+  Status   = Ext4Read (Partition, File, SymlinkTmp, File->Position, &ReadSize);
+  if (!EFI_ERROR (Status)) {
+    File->Position += ReadSize;
+  } else {
+    DEBUG ((DEBUG_FS, "[ext4] Failed to read symlink from blocks with Status %r\n", Status));
+    FreePool (SymlinkTmp);
+    return Status;
+  }
+
+  //
+  // Add null-terminator
+  //
+  SymlinkTmp[SymlinkSizeTmp] = '\0';
+
+  //
+  // It is not clear, should we check that symlink allocation size is
+  // equal symlink string size or not. However there is no checks in existing
+  // Ext4 implementations, so we also don't check it here relying on the fact
+  // we terminated string ourselves above.
+  //
+  // ASSERT (SymlinkAllocateSize == AsciiStrSize (SymlinkTmp));
+  //
+
+  if (SymlinkSizeTmp != ReadSize) {
+    DEBUG ((
+      DEBUG_FS,
+      "[ext4] Error! The sz of the read block doesn't match the value from the inode!\n"
+      ));
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  *AsciiSymlinkSize = SymlinkAllocateSize;
+  *AsciiSymlink     = SymlinkTmp;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads a symlink file.
+
+  @param[in]      Partition   Pointer to the ext4 partition.
+  @param[in]      File        Pointer to the open symlink file.
+  @param[out]     Symlink     Pointer to the output unicode symlink string.
+
+  @retval EFI_SUCCESS           Symlink was read.
+  @retval EFI_ACCESS_DENIED     Symlink is encrypted.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation error.
+  @retval EFI_INVALID_PARAMETER Symlink path has incorrect length
+  @retval EFI_VOLUME_CORRUPTED  Symlink read block size differ from inode value
+**/
+EFI_STATUS
+Ext4ReadSymlink (
+  IN     EXT4_PARTITION  *Partition,
+  IN     EXT4_FILE       *File,
+  OUT    CHAR16          **Symlink
+  )
+{
+  EFI_STATUS  Status;
+  CHAR8       *SymlinkTmp;
+  UINT32      SymlinkSize;
+  CHAR16      *Symlink16Tmp;
+  CHAR16      *Needle;
+
+  //
+  // Assume that we alread read Inode via Ext4ReadInode
+  // Skip reading, just check encryption flag
+  //
+  if ((File->Inode->i_flags & EXT4_ENCRYPT_FL) != 0) {
+    Status = EFI_ACCESS_DENIED;
+    DEBUG ((DEBUG_FS, "[ext4] Error, symlink is encrypted\n"));
+    return Status;
+  }
+
+  if (Ext4SymlinkIsFastSymlink (File)) {
+    Status = Ext4ReadFastSymlink (Partition, File, &SymlinkTmp, &SymlinkSize);
+  } else {
+    Status = Ext4ReadSlowSymlink (Partition, File, &SymlinkTmp, &SymlinkSize);
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_FS, "[ext4] Symlink read error with Status %r\n", Status));
+    return Status;
+  }
+
+  Symlink16Tmp = AllocateZeroPool (SymlinkSize * sizeof (CHAR16));
+  if (Symlink16Tmp == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink unicode string buffer\n"));
+    FreePool (SymlinkTmp);
+    return Status;
+  }
+
+  Status = AsciiStrToUnicodeStrS (
+             SymlinkTmp,
+             Symlink16Tmp,
+             SymlinkSize
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_FS,
+      "[ext4] Failed to convert ascii symlink to unicode with Status %r\n",
+      Status
+      ));
+    FreePool (Symlink16Tmp);
+    FreePool (SymlinkTmp);
+    return Status;
+  }
+
+  //
+  // Convert to UEFI slashes
+  //
+  Needle = Symlink16Tmp;
+  while ((Needle = StrStr (Needle, L"/")) != NULL) {
+    *Needle++ = L'\\';
+  }
+
+  *Symlink = Symlink16Tmp;
+
+  FreePool (SymlinkTmp);
+  return Status;
+}
+
 /**
   Opens a new file relative to the source file's location.
 
-  @param[in]  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
+  @param[out] FoundFile  A pointer to the location to return the opened handle for the new
+                         file.
+  @param[in]  Source     A pointer to the EXT4_FILE instance that is the file
                          handle to the source location. This would typically be an open
                          handle to a directory.
-  @param[out] NewHandle  A pointer to the location to return the opened handle for the new
-                         file.
   @param[in]  FileName   The Null-terminated string of the name of the file to be opened.
                          The file name may contain the following path modifiers: "\", ".",
                          and "..".
@@ -165,13 +381,12 @@ Ext4DirCanLookup (
 
 **/
 EFI_STATUS
-EFIAPI
-Ext4Open (
-  IN EFI_FILE_PROTOCOL   *This,
-  OUT EFI_FILE_PROTOCOL  **NewHandle,
-  IN CHAR16              *FileName,
-  IN UINT64              OpenMode,
-  IN UINT64              Attributes
+Ext4OpenInternal (
+  OUT EXT4_FILE  **FoundFile,
+  IN  EXT4_FILE  *Source,
+  IN  CHAR16     *FileName,
+  IN  UINT64     OpenMode,
+  IN  UINT64     Attributes
   )
 {
   EXT4_FILE       *Current;
@@ -180,13 +395,14 @@ Ext4Open (
   CHAR16          PathSegment[EXT4_NAME_MAX + 1];
   UINTN           Length;
   EXT4_FILE       *File;
+  CHAR16          *Symlink;
   EFI_STATUS      Status;
 
-  Current   = (EXT4_FILE *)This;
+  Current   = Source;
   Partition = Current->Partition;
   Level     = 0;
 
-  DEBUG ((DEBUG_FS, "[ext4] Ext4Open %s\n", FileName));
+  DEBUG ((DEBUG_FS, "[ext4] Ext4OpenInternal %s\n", FileName));
   // If the path starts with a backslash, we treat the root directory as the base directory
   if (FileName[0] == L'\\') {
     FileName++;
@@ -194,6 +410,11 @@ Ext4Open (
   }
 
   while (FileName[0] != L'\0') {
+    if (Partition->Root->Symloops > SYMLOOP_MAX) {
+      DEBUG ((DEBUG_FS, "[ext4] Symloop limit is hit !\n"));
+      return EFI_ACCESS_DENIED;
+    }
+
     // Discard leading path separators
     while (FileName[0] == L'\\') {
       FileName++;
@@ -238,18 +459,45 @@ Ext4Open (
     }
 
     // Check if this is a valid file to open in EFI
-
-    // What to do with symlinks? They're nonsense when absolute but may
-    // be useful when they're relative. Right now, they're ignored, since they
-    // bring a lot of trouble for something that's not as useful in our case.
-    // If you want to link, use hard links.
-
     if (!Ext4FileIsOpenable (File)) {
       Ext4CloseInternal (File);
       // This looks like an /okay/ status to return.
       return EFI_ACCESS_DENIED;
     }
 
+    //
+    // Reading symlink and then trying to follow it
+    //
+    if (Ext4FileIsSymlink (File)) {
+      Partition->Root->Symloops++;
+      DEBUG ((DEBUG_FS, "[ext4] File %s is symlink, trying to read it\n", PathSegment));
+      Status = Ext4ReadSymlink (Partition, File, &Symlink);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_FS, "[ext4] Error reading %s symlink!\n", PathSegment));
+        return Status;
+      }
+
+      DEBUG ((DEBUG_FS, "[ext4] File %s is linked to %s\n", PathSegment, Symlink));
+      //
+      // Close symlink file
+      //
+      Ext4CloseInternal (File);
+      //
+      // Open linked file by recursive call of Ext4OpenFile
+      //
+      Status = Ext4OpenInternal (FoundFile, Current, Symlink, OpenMode, Attributes);
+      FreePool (Symlink);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_FS, "[ext4] Error opening linked file %s\n", Symlink));
+        return Status;
+      }
+
+      //
+      // Set File to newly opened
+      //
+      File = *FoundFile;
+    }
+
     if (Level != 0) {
       // Careful not to close the base directory
       Ext4CloseInternal (Current);
@@ -273,12 +521,75 @@ Ext4Open (
     return EFI_ACCESS_DENIED;
   }
 
-  *NewHandle = &Current->Protocol;
+  *FoundFile = Current;
 
   DEBUG ((DEBUG_FS, "[ext4] Opened filename %s\n", Current->Dentry->Name));
   return EFI_SUCCESS;
 }
 
+/**
+  Opens a new file relative to the source file's location.
+  @param[in]  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                         handle to the source location. This would typically be an open
+                         handle to a directory.
+  @param[out] NewHandle  A pointer to the location to return the opened handle for the new
+                         file.
+  @param[in]  FileName   The Null-terminated string of the name of the file to be opened.
+                         The file name may contain the following path modifiers: "\", ".",
+                         and "..".
+  @param[in]  OpenMode   The mode to open the file. The only valid combinations that the
+                         file may be opened with are: Read, Read/Write, or Create/Read/Write.
+  @param[in]  Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
+                         attribute bits for the newly created file.
+  @retval EFI_SUCCESS          The file was opened.
+  @retval EFI_NOT_FOUND        The specified file could not be found on the device.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
+                               longer supported.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  An attempt was made to create a file, or open a file for write
+                               when the media is write-protected.
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
+  @retval EFI_VOLUME_FULL      The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+Ext4Open (
+  IN EFI_FILE_PROTOCOL   *This,
+  OUT EFI_FILE_PROTOCOL  **NewHandle,
+  IN CHAR16              *FileName,
+  IN UINT64              OpenMode,
+  IN UINT64              Attributes
+  )
+{
+  EFI_STATUS  Status;
+  EXT4_FILE   *FoundFile;
+  EXT4_FILE   *Source;
+
+  Source = (EXT4_FILE *)This;
+
+  //
+  // Reset Symloops counter
+  //
+  Source->Partition->Root->Symloops = 0;
+
+  Status = Ext4OpenInternal (
+             &FoundFile,
+             Source,
+             FileName,
+             OpenMode,
+             Attributes
+             );
+
+  if (!EFI_ERROR (Status)) {
+    *NewHandle = &FoundFile->Protocol;
+  }
+
+  return Status;
+}
+
 /**
   Closes a specified file handle.
 
@@ -588,7 +899,7 @@ Ext4GetVolumeName (
 
   // s_volume_name is only valid on dynamic revision; old filesystems don't support this
   if (Partition->SuperBlock.s_rev_level == EXT4_DYNAMIC_REV) {
-    CopyMem (TempVolName, (CONST CHAR8 *)Partition->SuperBlock.s_volume_name, 16);
+    CopyMem (TempVolName, Partition->SuperBlock.s_volume_name, 16);
     TempVolName[16] = '\0';
 
     Status = UTF8StrToUCS2 (TempVolName, &VolumeName);
@@ -754,12 +1065,14 @@ Ext4GetInfo (
   OUT VOID              *Buffer
   )
 {
+  EXT4_FILE       *File;
   EXT4_PARTITION  *Partition;
 
-  Partition = ((EXT4_FILE *)This)->Partition;
+  File      = (EXT4_FILE *)This;
+  Partition = File->Partition;
 
   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
-    return Ext4GetFileInfo ((EXT4_FILE *)This, Buffer, BufferSize);
+    return Ext4GetFileInfo (File, Buffer, BufferSize);
   }
 
   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
@@ -870,12 +1183,12 @@ Ext4SetInfo (
   )
 {
   EXT4_FILE       *File;
-  EXT4_PARTITION  *Part;
+  EXT4_PARTITION  *Partition;
 
-  File = (EXT4_FILE *)This;
-  Part = File->Partition;
+  File      = (EXT4_FILE *)This;
+  Partition = File->Partition;
 
-  if (Part->ReadOnly) {
+  if (Partition->ReadOnly) {
     return EFI_WRITE_PROTECTED;
   }
 
diff --git a/Features/Ext4Pkg/Ext4Dxe/Inode.c b/Features/Ext4Pkg/Ext4Dxe/Inode.c
index 831f5946e870..e95299c3aee0 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Inode.c
+++ b/Features/Ext4Pkg/Ext4Dxe/Inode.c
@@ -255,6 +255,44 @@ Ext4FileIsDir (
   return (File->Inode->i_mode & EXT4_INO_TYPE_DIR) == EXT4_INO_TYPE_DIR;
 }
 
+/**
+   Checks if a file is a symlink.
+   @param[in]      File          Pointer to the opened file.
+
+   @return TRUE if file is a symlink.
+**/
+BOOLEAN
+Ext4FileIsSymlink (
+  IN CONST EXT4_FILE  *File
+  )
+{
+  return (File->Inode->i_mode & EXT4_INO_TYPE_SYMLINK) == EXT4_INO_TYPE_SYMLINK;
+}
+
+/**
+   Detects if a symlink is a fast symlink.
+   @param[in]      File          Pointer to the opened file.
+
+   @return TRUE if file is a fast symlink.
+**/
+BOOLEAN
+Ext4SymlinkIsFastSymlink (
+  IN CONST EXT4_FILE  *File
+  )
+{
+  //
+  // REF: https://github.com/heatd/Onyx/blob/master/kernel/kernel/fs/ext2/symlink.cpp#L26
+  // Essentially, we're comparing the extended attribute blocks
+  // with the inode's i_blocks, and if it's zero we know the inode isn't storing
+  // the link in filesystem blocks, so we look to the ext2_inode->i_data.
+  //
+  INTN  ExtAttrBlocks = File->Inode->i_file_acl ? (File->Partition->BlockSize >> 9) : 0;
+
+  return (  File->Inode->i_blocks == ExtAttrBlocks
+         && EXT4_INODE_SIZE (File->Inode) <= 60
+            );
+}
+
 /**
    Checks if a file is a regular file.
    @param[in]      File          Pointer to the opened file.
-- 
2.37.0


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

* [edk2-platforms][PATCH v2 2/2] Ext4Pkg: Add base containing record macro for EXT4_FILE
  2022-07-20  6:47 [edk2-platforms][PATCH v2 0/2] Ext4Pkg: Add Symbolic Links support Savva Mitrofanov
  2022-07-20  6:47 ` [edk2-platforms][PATCH v2 1/2] Ext4Pkg: Add symbolic links support Savva Mitrofanov
@ 2022-07-20  6:47 ` Savva Mitrofanov
  2022-07-20 17:48   ` Marvin Häuser
  1 sibling, 1 reply; 4+ messages in thread
From: Savva Mitrofanov @ 2022-07-20  6:47 UTC (permalink / raw)
  To: devel; +Cc: Marvin Häuser, Pedro Falcato, Vitaly Cheptsov

We shouldn't use direct casts, because in the future it could break
the code, so using BASE_CR would be safe against possible structure
changes and rearrangements

Cc: Marvin Häuser <mhaeuser@posteo.de>
Cc: Pedro Falcato <pedro.falcato@gmail.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>
Signed-off-by: Savva Mitrofanov <savvamtr@gmail.com>
---
 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h |  2 ++
 Features/Ext4Pkg/Ext4Dxe/File.c    | 16 ++++++++--------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
index a1eb32aa2cff..3ff7b29e7133 100644
--- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -383,6 +383,8 @@ struct _Ext4File {
   EXT4_DENTRY           *Dentry;
 };
 
+#define EXT4_FILE_FROM_THIS(This)  BASE_CR ((This), EXT4_FILE, Protocol)
+
 #define EXT4_FILE_FROM_OPEN_FILES_NODE(Node)                                   \
   BASE_CR(Node, EXT4_FILE, OpenFilesListNode)
 
diff --git a/Features/Ext4Pkg/Ext4Dxe/File.c b/Features/Ext4Pkg/Ext4Dxe/File.c
index 0fb9e05e6647..750397010443 100644
--- a/Features/Ext4Pkg/Ext4Dxe/File.c
+++ b/Features/Ext4Pkg/Ext4Dxe/File.c
@@ -568,7 +568,7 @@ Ext4Open (
   EXT4_FILE   *FoundFile;
   EXT4_FILE   *Source;
 
-  Source = (EXT4_FILE *)This;
+  Source = EXT4_FILE_FROM_THIS (This);
 
   //
   // Reset Symloops counter
@@ -605,7 +605,7 @@ Ext4Close (
   IN EFI_FILE_PROTOCOL  *This
   )
 {
-  return Ext4CloseInternal ((EXT4_FILE *)This);
+  return Ext4CloseInternal (EXT4_FILE_FROM_THIS (This));
 }
 
 /**
@@ -686,7 +686,7 @@ Ext4ReadFile (
   EXT4_PARTITION  *Partition;
   EFI_STATUS      Status;
 
-  File      = (EXT4_FILE *)This;
+  File      = EXT4_FILE_FROM_THIS (This);
   Partition = File->Partition;
 
   ASSERT (Ext4FileIsOpenable (File));
@@ -737,7 +737,7 @@ Ext4WriteFile (
 {
   EXT4_FILE  *File;
 
-  File = (EXT4_FILE *)This;
+  File = EXT4_FILE_FROM_THIS (This);
 
   if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
     return EFI_ACCESS_DENIED;
@@ -767,7 +767,7 @@ Ext4GetPosition (
 {
   EXT4_FILE  *File;
 
-  File = (EXT4_FILE *)This;
+  File = EXT4_FILE_FROM_THIS (This);
 
   if (Ext4FileIsDir (File)) {
     return EFI_UNSUPPORTED;
@@ -800,7 +800,7 @@ Ext4SetPosition (
 {
   EXT4_FILE  *File;
 
-  File = (EXT4_FILE *)This;
+  File = EXT4_FILE_FROM_THIS (This);
 
   // Only seeks to 0 (so it resets the ReadDir operation) are allowed
   if (Ext4FileIsDir (File) && (Position != 0)) {
@@ -1068,7 +1068,7 @@ Ext4GetInfo (
   EXT4_FILE       *File;
   EXT4_PARTITION  *Partition;
 
-  File      = (EXT4_FILE *)This;
+  File      = EXT4_FILE_FROM_THIS (This);
   Partition = File->Partition;
 
   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
@@ -1185,7 +1185,7 @@ Ext4SetInfo (
   EXT4_FILE       *File;
   EXT4_PARTITION  *Partition;
 
-  File      = (EXT4_FILE *)This;
+  File      = EXT4_FILE_FROM_THIS (This);
   Partition = File->Partition;
 
   if (Partition->ReadOnly) {
-- 
2.37.0


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

* Re: [edk2-platforms][PATCH v2 2/2] Ext4Pkg: Add base containing record macro for EXT4_FILE
  2022-07-20  6:47 ` [edk2-platforms][PATCH v2 2/2] Ext4Pkg: Add base containing record macro for EXT4_FILE Savva Mitrofanov
@ 2022-07-20 17:48   ` Marvin Häuser
  0 siblings, 0 replies; 4+ messages in thread
From: Marvin Häuser @ 2022-07-20 17:48 UTC (permalink / raw)
  To: Savva Mitrofanov; +Cc: edk2-devel-groups-io, Pedro Falcato, Vitaly Cheptsov

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

> On 20. Jul 2022, at 08:47, Savva Mitrofanov <savvamtr@gmail.com> wrote:
> 
> We shouldn't use direct casts, because in the future it could break
> the code, so using BASE_CR would be safe against possible structure
> changes and rearrangements
> 
> Cc: Marvin Häuser <mhaeuser@posteo.de>
> Cc: Pedro Falcato <pedro.falcato@gmail.com>
> Cc: Vitaly Cheptsov <vit9696@protonmail.com>
> Signed-off-by: Savva Mitrofanov <savvamtr@gmail.com>
> ---
> Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h |  2 ++
> Features/Ext4Pkg/Ext4Dxe/File.c    | 16 ++++++++--------
> 2 files changed, 10 insertions(+), 8 deletions(-)
> 
> diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> index a1eb32aa2cff..3ff7b29e7133 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
> @@ -383,6 +383,8 @@ struct _Ext4File {
>   EXT4_DENTRY           *Dentry;
> };
> 
> +#define EXT4_FILE_FROM_THIS(This)  BASE_CR ((This), EXT4_FILE, Protocol)
> +
> #define EXT4_FILE_FROM_OPEN_FILES_NODE(Node)                                   \
>   BASE_CR(Node, EXT4_FILE, OpenFilesListNode)
> 
> diff --git a/Features/Ext4Pkg/Ext4Dxe/File.c b/Features/Ext4Pkg/Ext4Dxe/File.c
> index 0fb9e05e6647..750397010443 100644
> --- a/Features/Ext4Pkg/Ext4Dxe/File.c
> +++ b/Features/Ext4Pkg/Ext4Dxe/File.c
> @@ -568,7 +568,7 @@ Ext4Open (
>   EXT4_FILE   *FoundFile;
>   EXT4_FILE   *Source;
> 
> -  Source = (EXT4_FILE *)This;
> +  Source = EXT4_FILE_FROM_THIS (This);
> 
>   //
>   // Reset Symloops counter
> @@ -605,7 +605,7 @@ Ext4Close (
>   IN EFI_FILE_PROTOCOL  *This
>   )
> {
> -  return Ext4CloseInternal ((EXT4_FILE *)This);
> +  return Ext4CloseInternal (EXT4_FILE_FROM_THIS (This));
> }
> 
> /**
> @@ -686,7 +686,7 @@ Ext4ReadFile (
>   EXT4_PARTITION  *Partition;
>   EFI_STATUS      Status;
> 
> -  File      = (EXT4_FILE *)This;
> +  File      = EXT4_FILE_FROM_THIS (This);
>   Partition = File->Partition;
> 
>   ASSERT (Ext4FileIsOpenable (File));
> @@ -737,7 +737,7 @@ Ext4WriteFile (
> {
>   EXT4_FILE  *File;
> 
> -  File = (EXT4_FILE *)This;
> +  File = EXT4_FILE_FROM_THIS (This);
> 
>   if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
>     return EFI_ACCESS_DENIED;
> @@ -767,7 +767,7 @@ Ext4GetPosition (
> {
>   EXT4_FILE  *File;
> 
> -  File = (EXT4_FILE *)This;
> +  File = EXT4_FILE_FROM_THIS (This);
> 
>   if (Ext4FileIsDir (File)) {
>     return EFI_UNSUPPORTED;
> @@ -800,7 +800,7 @@ Ext4SetPosition (
> {
>   EXT4_FILE  *File;
> 
> -  File = (EXT4_FILE *)This;
> +  File = EXT4_FILE_FROM_THIS (This);
> 
>   // Only seeks to 0 (so it resets the ReadDir operation) are allowed
>   if (Ext4FileIsDir (File) && (Position != 0)) {
> @@ -1068,7 +1068,7 @@ Ext4GetInfo (
>   EXT4_FILE       *File;
>   EXT4_PARTITION  *Partition;
> 
> -  File      = (EXT4_FILE *)This;
> +  File      = EXT4_FILE_FROM_THIS (This);
>   Partition = File->Partition;
> 
>   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
> @@ -1185,7 +1185,7 @@ Ext4SetInfo (
>   EXT4_FILE       *File;
>   EXT4_PARTITION  *Partition;
> 
> -  File      = (EXT4_FILE *)This;
> +  File      = EXT4_FILE_FROM_THIS (This);
>   Partition = File->Partition;
> 
>   if (Partition->ReadOnly) {
> -- 
> 2.37.0
> 


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

end of thread, other threads:[~2022-07-20 17:48 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-07-20  6:47 [edk2-platforms][PATCH v2 0/2] Ext4Pkg: Add Symbolic Links support Savva Mitrofanov
2022-07-20  6:47 ` [edk2-platforms][PATCH v2 1/2] Ext4Pkg: Add symbolic links support Savva Mitrofanov
2022-07-20  6:47 ` [edk2-platforms][PATCH v2 2/2] Ext4Pkg: Add base containing record macro for EXT4_FILE Savva Mitrofanov
2022-07-20 17:48   ` Marvin Häuser

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