mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-27 15:44:04 +02:00
Ext4Pkg: Various improvements based on Sydr fuzzing results.
Signed-off-by: Savva Mitrofanov <savvamtr@gmail.com>
This commit is contained in:
parent
76daa1e807
commit
8c29fe63c3
@ -50,6 +50,11 @@ Ext4ReadInode (
|
|||||||
EXT4_BLOCK_NR InodeTableStart;
|
EXT4_BLOCK_NR InodeTableStart;
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
if (!EXT4_IS_VALID_INODE_NR (Partition, InodeNum)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "[ext4] Error reading inode: inode number %lu isn't valid\n", InodeNum));
|
||||||
|
return EFI_VOLUME_CORRUPTED;
|
||||||
|
}
|
||||||
|
|
||||||
BlockGroupNumber = (UINT32)DivU64x64Remainder (
|
BlockGroupNumber = (UINT32)DivU64x64Remainder (
|
||||||
InodeNum - 1,
|
InodeNum - 1,
|
||||||
Partition->SuperBlock.s_inodes_per_group,
|
Partition->SuperBlock.s_inodes_per_group,
|
||||||
@ -164,14 +169,10 @@ Ext4CalculateBlockGroupDescChecksumGdtCsum (
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT16 Csum;
|
UINT16 Csum;
|
||||||
UINT16 Dummy;
|
|
||||||
|
|
||||||
Dummy = 0;
|
Csum = CalculateCrc16Ansi (Partition->SuperBlock.s_uuid, sizeof (Partition->SuperBlock.s_uuid), 0xFFFF);
|
||||||
|
|
||||||
Csum = CalculateCrc16Ansi (Partition->SuperBlock.s_uuid, 16, 0);
|
|
||||||
Csum = CalculateCrc16Ansi (&BlockGroupNum, sizeof (BlockGroupNum), Csum);
|
Csum = CalculateCrc16Ansi (&BlockGroupNum, sizeof (BlockGroupNum), Csum);
|
||||||
Csum = CalculateCrc16Ansi (BlockGroupDesc, OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_checksum), Csum);
|
Csum = CalculateCrc16Ansi (BlockGroupDesc, OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_checksum), Csum);
|
||||||
Csum = CalculateCrc16Ansi (&Dummy, sizeof (Dummy), Csum);
|
|
||||||
Csum =
|
Csum =
|
||||||
CalculateCrc16Ansi (
|
CalculateCrc16Ansi (
|
||||||
&BlockGroupDesc->bg_block_bitmap_hi,
|
&BlockGroupDesc->bg_block_bitmap_hi,
|
||||||
|
@ -131,7 +131,7 @@ Ext4GetBlockPath (
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Get an extent from a block map
|
@brief Get an extent from a block map
|
||||||
Note: Also parses file holes and creates uninitialised extents from them.
|
Note: Also parses file holes and creates uninitialized extents from them.
|
||||||
|
|
||||||
@param[in] Buffer Buffer of block pointers
|
@param[in] Buffer Buffer of block pointers
|
||||||
@param[in] IndEntries Number of entries in this block pointer table
|
@param[in] IndEntries Number of entries in this block pointer table
|
||||||
@ -173,7 +173,7 @@ Ext4GetExtentInBlockMap (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We mark the extent as uninitialised, although there's a difference between uninit
|
// We mark the extent as uninitialized, although there's a difference between uninit
|
||||||
// extents and file holes.
|
// extents and file holes.
|
||||||
Extent->ee_len = EXT4_EXTENT_MAX_INITIALIZED + Count;
|
Extent->ee_len = EXT4_EXTENT_MAX_INITIALIZED + Count;
|
||||||
return;
|
return;
|
||||||
@ -206,7 +206,7 @@ Ext4GetExtentInBlockMap (
|
|||||||
@param[in] LogicalBlock Block number which the returned extent must cover.
|
@param[in] LogicalBlock Block number which the returned extent must cover.
|
||||||
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
||||||
|
|
||||||
@retval EFI_SUCCESS Retrieval was succesful.
|
@retval EFI_SUCCESS Retrieval was successful.
|
||||||
@retval EFI_NO_MAPPING Block has no mapping.
|
@retval EFI_NO_MAPPING Block has no mapping.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Unicode collation routines
|
Unicode collation routines
|
||||||
|
|
||||||
Copyright (c) 2021 Pedro Falcato All rights reserved.
|
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||||
Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
|
Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
|
||||||
|
|
||||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <Uefi.h>
|
#include <Uefi.h>
|
||||||
|
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/UefiLib.h>
|
#include <Library/UefiLib.h>
|
||||||
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
@ -23,6 +24,21 @@ STATIC EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollationInterface = NULL;
|
|||||||
* PS: Maybe all this code could be put in a library? It looks heavily shareable.
|
* PS: Maybe all this code could be put in a library? It looks heavily shareable.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if unicode collation is initialized
|
||||||
|
|
||||||
|
@retval TRUE if Ext4InitialiseUnicodeCollation() was already called successfully
|
||||||
|
@retval FALSE if Ext4InitialiseUnicodeCollation() was not yet called successfully
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
BOOLEAN
|
||||||
|
Ext4IsCollationInitialized (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return gUnicodeCollationInterface != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Worker function to initialize Unicode Collation support.
|
Worker function to initialize Unicode Collation support.
|
||||||
|
|
||||||
@ -127,6 +143,11 @@ Ext4InitialiseUnicodeCollation (
|
|||||||
|
|
||||||
Status = EFI_UNSUPPORTED;
|
Status = EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
// If already done, just return success.
|
||||||
|
if (Ext4IsCollationInitialized ()) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// First try to use RFC 4646 Unicode Collation 2 Protocol.
|
// First try to use RFC 4646 Unicode Collation 2 Protocol.
|
||||||
//
|
//
|
||||||
@ -169,5 +190,6 @@ Ext4StrCmpInsensitive (
|
|||||||
IN CHAR16 *Str2
|
IN CHAR16 *Str2
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
ASSERT (gUnicodeCollationInterface != NULL);
|
||||||
return gUnicodeCollationInterface->StriColl (gUnicodeCollationInterface, Str1, Str2);
|
return gUnicodeCollationInterface->StriColl (gUnicodeCollationInterface, Str1, Str2);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Directory related routines
|
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
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
**/
|
**/
|
||||||
@ -16,7 +16,8 @@
|
|||||||
@param[in] Entry Pointer to a EXT4_DIR_ENTRY.
|
@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 The filename was succesfully retrieved and converted to UCS2.
|
@retval EFI_SUCCESS The filename was successfully retrieved and converted to UCS2.
|
||||||
|
@retval EFI_INVALID_PARAMETER The filename is not valid UTF-8.
|
||||||
@retval !EFI_SUCCESS Failure.
|
@retval !EFI_SUCCESS Failure.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -27,9 +28,16 @@ Ext4GetUcs2DirentName (
|
|||||||
{
|
{
|
||||||
CHAR8 Utf8NameBuf[EXT4_NAME_MAX + 1];
|
CHAR8 Utf8NameBuf[EXT4_NAME_MAX + 1];
|
||||||
UINT16 *Str;
|
UINT16 *Str;
|
||||||
|
UINT8 Index;
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
|
||||||
CopyMem (Utf8NameBuf, Entry->name, Entry->name_len);
|
for (Index = 0; Index < Entry->name_len; ++Index) {
|
||||||
|
if (Entry->name[Index] == '\0') {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utf8NameBuf[Index] = Entry->name[Index];
|
||||||
|
}
|
||||||
|
|
||||||
Utf8NameBuf[Entry->name_len] = '\0';
|
Utf8NameBuf[Entry->name_len] = '\0';
|
||||||
|
|
||||||
@ -112,7 +120,6 @@ Ext4RetrieveDirent (
|
|||||||
UINTN ToCopy;
|
UINTN ToCopy;
|
||||||
UINTN BlockOffset;
|
UINTN BlockOffset;
|
||||||
|
|
||||||
Status = EFI_NOT_FOUND;
|
|
||||||
Buf = AllocatePool (Partition->BlockSize);
|
Buf = AllocatePool (Partition->BlockSize);
|
||||||
|
|
||||||
if (Buf == NULL) {
|
if (Buf == NULL) {
|
||||||
@ -127,7 +134,8 @@ Ext4RetrieveDirent (
|
|||||||
DivU64x32Remainder (DirInoSize, Partition->BlockSize, &BlockRemainder);
|
DivU64x32Remainder (DirInoSize, Partition->BlockSize, &BlockRemainder);
|
||||||
if (BlockRemainder != 0) {
|
if (BlockRemainder != 0) {
|
||||||
// Directory inodes need to have block aligned sizes
|
// Directory inodes need to have block aligned sizes
|
||||||
return EFI_VOLUME_CORRUPTED;
|
Status = EFI_VOLUME_CORRUPTED;
|
||||||
|
goto Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (Off < DirInoSize) {
|
while (Off < DirInoSize) {
|
||||||
@ -136,8 +144,7 @@ Ext4RetrieveDirent (
|
|||||||
Status = Ext4Read (Partition, Directory, Buf, Off, &Length);
|
Status = Ext4Read (Partition, Directory, Buf, Off, &Length);
|
||||||
|
|
||||||
if (Status != EFI_SUCCESS) {
|
if (Status != EFI_SUCCESS) {
|
||||||
FreePool (Buf);
|
goto Out;
|
||||||
return Status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (BlockOffset = 0; BlockOffset < Partition->BlockSize; ) {
|
for (BlockOffset = 0; BlockOffset < Partition->BlockSize; ) {
|
||||||
@ -145,19 +152,19 @@ Ext4RetrieveDirent (
|
|||||||
RemainingBlock = Partition->BlockSize - BlockOffset;
|
RemainingBlock = Partition->BlockSize - BlockOffset;
|
||||||
// Check if the minimum directory entry fits inside [BlockOffset, EndOfBlock]
|
// Check if the minimum directory entry fits inside [BlockOffset, EndOfBlock]
|
||||||
if (RemainingBlock < EXT4_MIN_DIR_ENTRY_LEN) {
|
if (RemainingBlock < EXT4_MIN_DIR_ENTRY_LEN) {
|
||||||
FreePool (Buf);
|
Status = EFI_VOLUME_CORRUPTED;
|
||||||
return EFI_VOLUME_CORRUPTED;
|
goto Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Ext4ValidDirent (Entry)) {
|
if (!Ext4ValidDirent (Entry)) {
|
||||||
FreePool (Buf);
|
Status = EFI_VOLUME_CORRUPTED;
|
||||||
return EFI_VOLUME_CORRUPTED;
|
goto Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Entry->name_len > RemainingBlock) || (Entry->rec_len > RemainingBlock)) {
|
if ((Entry->name_len > RemainingBlock) || (Entry->rec_len > RemainingBlock)) {
|
||||||
// Corrupted filesystem
|
// Corrupted filesystem
|
||||||
FreePool (Buf);
|
Status = EFI_VOLUME_CORRUPTED;
|
||||||
return EFI_VOLUME_CORRUPTED;
|
goto Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unused entry
|
// Unused entry
|
||||||
@ -174,20 +181,26 @@ Ext4RetrieveDirent (
|
|||||||
* need to form valid ASCII/UTF-8 sequences.
|
* need to form valid ASCII/UTF-8 sequences.
|
||||||
*/
|
*/
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
// If we error out, skip this entry
|
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.
|
// I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
|
||||||
BlockOffset += Entry->rec_len;
|
BlockOffset += Entry->rec_len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Other sorts of errors should just error out.
|
||||||
|
FreePool (Buf);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
if ((Entry->name_len == StrLen (Name)) &&
|
if ((Entry->name_len == StrLen (Name)) &&
|
||||||
!Ext4StrCmpInsensitive (DirentUcs2Name, (CHAR16 *)Name))
|
!Ext4StrCmpInsensitive (DirentUcs2Name, (CHAR16 *)Name))
|
||||||
{
|
{
|
||||||
ToCopy = MIN (Entry->rec_len, sizeof (EXT4_DIR_ENTRY));
|
ToCopy = MIN (Entry->rec_len, sizeof (EXT4_DIR_ENTRY));
|
||||||
|
|
||||||
CopyMem (Result, Entry, ToCopy);
|
CopyMem (Result, Entry, ToCopy);
|
||||||
FreePool (Buf);
|
Status = EFI_SUCCESS;
|
||||||
return EFI_SUCCESS;
|
goto Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockOffset += Entry->rec_len;
|
BlockOffset += Entry->rec_len;
|
||||||
@ -196,8 +209,11 @@ Ext4RetrieveDirent (
|
|||||||
Off += Partition->BlockSize;
|
Off += Partition->BlockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status = EFI_NOT_FOUND;
|
||||||
|
|
||||||
|
Out:
|
||||||
FreePool (Buf);
|
FreePool (Buf);
|
||||||
return EFI_NOT_FOUND;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,13 +264,18 @@ Ext4OpenDirent (
|
|||||||
// Using the parent's parent's dentry
|
// Using the parent's parent's dentry
|
||||||
File->Dentry = Directory->Dentry->Parent;
|
File->Dentry = Directory->Dentry->Parent;
|
||||||
|
|
||||||
ASSERT (File->Dentry != NULL);
|
if (!File->Dentry) {
|
||||||
|
// Someone tried .. on root, so direct them to /
|
||||||
|
// This is an illegal EFI Open() but is possible to hit from a variety of internal code
|
||||||
|
File->Dentry = Directory->Dentry;
|
||||||
|
}
|
||||||
|
|
||||||
Ext4RefDentry (File->Dentry);
|
Ext4RefDentry (File->Dentry);
|
||||||
} else {
|
} else {
|
||||||
File->Dentry = Ext4CreateDentry (FileName, Directory->Dentry);
|
File->Dentry = Ext4CreateDentry (FileName, Directory->Dentry);
|
||||||
|
|
||||||
if (!File->Dentry) {
|
if (File->Dentry == NULL) {
|
||||||
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,6 +457,7 @@ Ext4ReadDir (
|
|||||||
EXT4_FILE *TempFile;
|
EXT4_FILE *TempFile;
|
||||||
BOOLEAN ShouldSkip;
|
BOOLEAN ShouldSkip;
|
||||||
BOOLEAN IsDotOrDotDot;
|
BOOLEAN IsDotOrDotDot;
|
||||||
|
CHAR16 DirentUcs2Name[EXT4_NAME_MAX + 1];
|
||||||
|
|
||||||
DirIno = File->Inode;
|
DirIno = File->Inode;
|
||||||
Status = EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
@ -491,18 +513,35 @@ Ext4ReadDir (
|
|||||||
// or a checksum at the end of the directory block.
|
// or a checksum at the end of the directory block.
|
||||||
// memcmp (and CompareMem) return 0 when the passed length is 0.
|
// memcmp (and CompareMem) return 0 when the passed length is 0.
|
||||||
|
|
||||||
IsDotOrDotDot = Entry.name_len != 0 &&
|
// We must bound name_len as > 0 and <= 2 to avoid any out-of-bounds accesses or bad detection of
|
||||||
(CompareMem (Entry.name, ".", Entry.name_len) == 0 ||
|
// "." and "..".
|
||||||
CompareMem (Entry.name, "..", Entry.name_len) == 0);
|
IsDotOrDotDot = Entry.name_len > 0 && Entry.name_len <= 2 &&
|
||||||
|
CompareMem (Entry.name, "..", Entry.name_len) == 0;
|
||||||
|
|
||||||
// When inode = 0, it's unused.
|
// When inode = 0, it's unused. When name_len == 0, it's a nameless entry
|
||||||
ShouldSkip = Entry.inode == 0 || IsDotOrDotDot;
|
// (which we should not expose to ReadDir).
|
||||||
|
ShouldSkip = Entry.inode == 0 || Entry.name_len == 0 || IsDotOrDotDot;
|
||||||
|
|
||||||
if (ShouldSkip) {
|
if (ShouldSkip) {
|
||||||
Offset += Entry.rec_len;
|
Offset += Entry.rec_len;
|
||||||
continue;
|
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);
|
Status = Ext4OpenDirent (Partition, EFI_FILE_MODE_READ, &TempFile, &Entry, File);
|
||||||
|
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
|
@ -54,17 +54,20 @@ Ext4ReadBlocks (
|
|||||||
UINT64 Offset;
|
UINT64 Offset;
|
||||||
UINTN Length;
|
UINTN Length;
|
||||||
|
|
||||||
|
ASSERT (NumberBlocks != 0);
|
||||||
|
ASSERT (BlockNumber != EXT4_BLOCK_FILE_HOLE);
|
||||||
|
|
||||||
Offset = MultU64x32 (BlockNumber, Partition->BlockSize);
|
Offset = MultU64x32 (BlockNumber, Partition->BlockSize);
|
||||||
Length = NumberBlocks * Partition->BlockSize;
|
Length = NumberBlocks * Partition->BlockSize;
|
||||||
|
|
||||||
// Check for overflow on the block -> byte conversions.
|
// Check for overflow on the block -> byte conversions.
|
||||||
// Partition->BlockSize is never 0, so we don't need to check for that.
|
// Partition->BlockSize is never 0, so we don't need to check for that.
|
||||||
|
|
||||||
if (Offset > DivU64x32 ((UINT64)-1, Partition->BlockSize)) {
|
if (DivU64x64Remainder (Offset, BlockNumber, NULL) != Partition->BlockSize) {
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Length > (UINTN)-1/Partition->BlockSize) {
|
if (Length / NumberBlocks != Partition->BlockSize) {
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +95,21 @@ Ext4AllocAndReadBlocks (
|
|||||||
VOID *Buf;
|
VOID *Buf;
|
||||||
UINTN Length;
|
UINTN Length;
|
||||||
|
|
||||||
|
// Check that number of blocks isn't empty, because
|
||||||
|
// this is incorrect condition for opened partition,
|
||||||
|
// so we just early-exit
|
||||||
|
if ((NumberBlocks == 0) || (BlockNumber == EXT4_BLOCK_FILE_HOLE)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Length = NumberBlocks * Partition->BlockSize;
|
Length = NumberBlocks * Partition->BlockSize;
|
||||||
|
|
||||||
if (Length > (UINTN)-1/Partition->BlockSize) {
|
// Check for integer overflow
|
||||||
|
if (Length / NumberBlocks != Partition->BlockSize) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buf = AllocatePool (Length);
|
Buf = AllocatePool (Length);
|
||||||
|
|
||||||
if (Buf == NULL) {
|
if (Buf == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Raw filesystem data structures
|
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
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
Layout of an EXT2/3/4 filesystem:
|
Layout of an EXT2/3/4 filesystem:
|
||||||
@ -397,12 +397,29 @@ typedef struct _Ext4Inode {
|
|||||||
UINT32 i_projid;
|
UINT32 i_projid;
|
||||||
} EXT4_INODE;
|
} EXT4_INODE;
|
||||||
|
|
||||||
|
#define EXT4_NAME_MAX 255
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
// offset 0x0: inode number (if 0, unused entry, should skip.)
|
||||||
UINT32 inode;
|
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;
|
UINT16 rec_len;
|
||||||
|
// offset 0x6: Directory entry's name's length
|
||||||
UINT8 name_len;
|
UINT8 name_len;
|
||||||
|
// offset 0x7: Directory entry's file type indicator
|
||||||
UINT8 file_type;
|
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;
|
} EXT4_DIR_ENTRY;
|
||||||
|
|
||||||
#define EXT4_MIN_DIR_ENTRY_LEN 8
|
#define EXT4_MIN_DIR_ENTRY_LEN 8
|
||||||
@ -467,8 +484,17 @@ typedef UINT64 EXT4_BLOCK_NR;
|
|||||||
typedef UINT32 EXT2_BLOCK_NR;
|
typedef UINT32 EXT2_BLOCK_NR;
|
||||||
typedef UINT32 EXT4_INO_NR;
|
typedef UINT32 EXT4_INO_NR;
|
||||||
|
|
||||||
// 2 is always the root inode number in ext4
|
/* Special inode numbers */
|
||||||
#define EXT4_ROOT_INODE_NR 2
|
#define EXT4_ROOT_INODE_NR 2
|
||||||
|
#define EXT4_USR_QUOTA_INODE_NR 3
|
||||||
|
#define EXT4_GRP_QUOTA_INODE_NR 4
|
||||||
|
#define EXT4_BOOT_LOADER_INODE_NR 5
|
||||||
|
#define EXT4_UNDEL_DIR_INODE_NR 6
|
||||||
|
#define EXT4_RESIZE_INODE_NR 7
|
||||||
|
#define EXT4_JOURNAL_INODE_NR 8
|
||||||
|
|
||||||
|
/* First non-reserved inode for old ext4 filesystems */
|
||||||
|
#define EXT4_GOOD_OLD_FIRST_INODE_NR 11
|
||||||
|
|
||||||
#define EXT4_BLOCK_FILE_HOLE 0
|
#define EXT4_BLOCK_FILE_HOLE 0
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Driver entry point
|
Driver entry point
|
||||||
|
|
||||||
Copyright (c) 2021 Pedro Falcato All rights reserved.
|
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@ -513,9 +513,7 @@ Ext4EntryPoint (
|
|||||||
IN EFI_SYSTEM_TABLE *SystemTable
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
return EfiLibInstallAllDriverProtocols2 (
|
||||||
|
|
||||||
Status = EfiLibInstallAllDriverProtocols2 (
|
|
||||||
ImageHandle,
|
ImageHandle,
|
||||||
SystemTable,
|
SystemTable,
|
||||||
&gExt4BindingProtocol,
|
&gExt4BindingProtocol,
|
||||||
@ -527,12 +525,6 @@ Ext4EntryPoint (
|
|||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ext4InitialiseUnicodeCollation (ImageHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -761,6 +753,17 @@ Ext4Bind (
|
|||||||
BlockIo = NULL;
|
BlockIo = NULL;
|
||||||
DiskIo = NULL;
|
DiskIo = NULL;
|
||||||
|
|
||||||
|
// Note: We initialize collation here since this is called in BDS, when we are likely
|
||||||
|
// to have the Unicode Collation protocols available.
|
||||||
|
Status = Ext4InitialiseUnicodeCollation (BindingProtocol->ImageHandle);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
// Lets throw a loud error into the log
|
||||||
|
// It is very unlikely something like this may fire out of the blue. Chances are either
|
||||||
|
// the platform configuration is wrong, or we are.
|
||||||
|
DEBUG ((DEBUG_ERROR, "[ext4] Error: Unicode Collation not available - failure to Start() - error %r\n", Status));
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
Status = gBS->OpenProtocol (
|
Status = gBS->OpenProtocol (
|
||||||
ControllerHandle,
|
ControllerHandle,
|
||||||
&gEfiDiskIoProtocolGuid,
|
&gEfiDiskIoProtocolGuid,
|
||||||
@ -774,7 +777,7 @@ Ext4Bind (
|
|||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "[Ext4] Controller supports DISK_IO\n"));
|
DEBUG ((DEBUG_INFO, "[ext4] Controller supports DISK_IO\n"));
|
||||||
|
|
||||||
Status = gBS->OpenProtocol (
|
Status = gBS->OpenProtocol (
|
||||||
ControllerHandle,
|
ControllerHandle,
|
||||||
@ -787,7 +790,7 @@ Ext4Bind (
|
|||||||
// It's okay to not support DISK_IO2
|
// It's okay to not support DISK_IO2
|
||||||
|
|
||||||
if (DiskIo2 != NULL) {
|
if (DiskIo2 != NULL) {
|
||||||
DEBUG ((DEBUG_INFO, "[Ext4] Controller supports DISK_IO2\n"));
|
DEBUG ((DEBUG_INFO, "[ext4] Controller supports DISK_IO2\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = gBS->OpenProtocol (
|
Status = gBS->OpenProtocol (
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Common header for the driver
|
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
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@ -32,7 +32,6 @@
|
|||||||
#include "Ext4Disk.h"
|
#include "Ext4Disk.h"
|
||||||
|
|
||||||
#define SYMLOOP_MAX 8
|
#define SYMLOOP_MAX 8
|
||||||
#define EXT4_NAME_MAX 255
|
|
||||||
//
|
//
|
||||||
// We need to specify path length limit for security purposes, to prevent possible
|
// 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,
|
// overflows and dead-loop conditions. Originally this limit is absent in FS design,
|
||||||
@ -41,6 +40,20 @@
|
|||||||
#define EXT4_EFI_PATH_MAX 4096
|
#define EXT4_EFI_PATH_MAX 4096
|
||||||
#define EXT4_DRIVER_VERSION 0x0000
|
#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 large 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.
|
Opens an ext4 partition and installs the Simple File System protocol.
|
||||||
|
|
||||||
@ -156,7 +169,7 @@ Ext4UnrefDentry (
|
|||||||
|
|
||||||
@param[out] Partition Partition structure to fill with filesystem
|
@param[out] Partition Partition structure to fill with filesystem
|
||||||
details.
|
details.
|
||||||
@retval EFI_SUCCESS Parsing was succesful and the partition is a
|
@retval EFI_SUCCESS Parsing was successful and the partition is a
|
||||||
valid ext4 partition.
|
valid ext4 partition.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -288,6 +301,16 @@ Ext4GetBlockGroupDesc (
|
|||||||
IN UINT32 BlockGroup
|
IN UINT32 BlockGroup
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks inode number validity across superblock of the opened partition.
|
||||||
|
|
||||||
|
@param[in] Partition Pointer to the opened ext4 partition.
|
||||||
|
|
||||||
|
@return TRUE if inode number is valid.
|
||||||
|
**/
|
||||||
|
#define EXT4_IS_VALID_INODE_NR(Partition, InodeNum) \
|
||||||
|
(((InodeNum) > 0) && (InodeNum) <= (Partition->SuperBlock.s_inodes_count))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads an inode from disk.
|
Reads an inode from disk.
|
||||||
|
|
||||||
@ -323,7 +346,7 @@ Ext4ReadInode (
|
|||||||
@param[out] Buffer Pointer to the buffer.
|
@param[out] Buffer Pointer to the buffer.
|
||||||
@param[in] Offset Offset of the read.
|
@param[in] Offset Offset of the read.
|
||||||
@param[in out] Length Pointer to the length of the buffer, in bytes.
|
@param[in out] Length Pointer to the length of the buffer, in bytes.
|
||||||
After a succesful read, it's updated to the
|
After a successful read, it's updated to the
|
||||||
number of read bytes.
|
number of read bytes.
|
||||||
|
|
||||||
@return Status of the read operation.
|
@return Status of the read operation.
|
||||||
@ -356,7 +379,7 @@ cover.
|
|||||||
@param[out] Extent Pointer to the output buffer, where the extent
|
@param[out] Extent Pointer to the output buffer, where the extent
|
||||||
will be copied to.
|
will be copied to.
|
||||||
|
|
||||||
@retval EFI_SUCCESS Retrieval was succesful.
|
@retval EFI_SUCCESS Retrieval was successful.
|
||||||
@retval EFI_NO_MAPPING Block has no mapping.
|
@retval EFI_NO_MAPPING Block has no mapping.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -945,10 +968,10 @@ Ext4StrCmpInsensitive (
|
|||||||
Retrieves the filename of the directory entry and converts it to UTF-16/UCS-2
|
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[in] Entry Pointer to a EXT4_DIR_ENTRY.
|
||||||
@param[out] Ucs2FileName Pointer to an array of CHAR16's, of size
|
@param[out] Ucs2FileName Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
|
||||||
EXT4_NAME_MAX + 1.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Unicode collation was successfully initialised.
|
@retval EFI_SUCCESS The filename was successfully retrieved and converted to UCS2.
|
||||||
|
@retval EFI_INVALID_PARAMETER The filename is not valid UTF-8.
|
||||||
@retval !EFI_SUCCESS Failure.
|
@retval !EFI_SUCCESS Failure.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -1107,7 +1130,7 @@ Ext4CalculateBlockGroupDescChecksum (
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Verifies the existance of a particular RO compat feature set.
|
Verifies the existence of a particular RO compat feature set.
|
||||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||||
@param[in] RoCompatFeatureSet Feature set to test.
|
@param[in] RoCompatFeatureSet Feature set to test.
|
||||||
|
|
||||||
@ -1117,7 +1140,7 @@ Ext4CalculateBlockGroupDescChecksum (
|
|||||||
((Partition->FeaturesRoCompat & RoCompatFeatureSet) == RoCompatFeatureSet)
|
((Partition->FeaturesRoCompat & RoCompatFeatureSet) == RoCompatFeatureSet)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Verifies the existance of a particular compat feature set.
|
Verifies the existence of a particular compat feature set.
|
||||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||||
@param[in] CompatFeatureSet Feature set to test.
|
@param[in] CompatFeatureSet Feature set to test.
|
||||||
|
|
||||||
@ -1127,7 +1150,7 @@ Ext4CalculateBlockGroupDescChecksum (
|
|||||||
((Partition->FeaturesCompat & CompatFeatureSet) == CompatFeatureSet)
|
((Partition->FeaturesCompat & CompatFeatureSet) == CompatFeatureSet)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Verifies the existance of a particular compat feature set.
|
Verifies the existence of a particular compat feature set.
|
||||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||||
@param[in] IncompatFeatureSet Feature set to test.
|
@param[in] IncompatFeatureSet Feature set to test.
|
||||||
|
|
||||||
@ -1218,7 +1241,7 @@ Ext4GetExtentLength (
|
|||||||
@param[in] LogicalBlock Block number which the returned extent must cover.
|
@param[in] LogicalBlock Block number which the returned extent must cover.
|
||||||
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
||||||
|
|
||||||
@retval EFI_SUCCESS Retrieval was succesful.
|
@retval EFI_SUCCESS Retrieval was successful.
|
||||||
@retval EFI_NO_MAPPING Block has no mapping.
|
@retval EFI_NO_MAPPING Block has no mapping.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Extent related routines
|
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
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@ -39,8 +39,11 @@ Ext4CalculateExtentChecksum (
|
|||||||
@param[in] File Pointer to the open file.
|
@param[in] File Pointer to the open file.
|
||||||
@param[in] Extents Pointer to an array of extents.
|
@param[in] Extents Pointer to an array of extents.
|
||||||
@param[in] NumberExtents Length of the array.
|
@param[in] NumberExtents Length of the array.
|
||||||
|
|
||||||
|
@return Result of the caching
|
||||||
**/
|
**/
|
||||||
VOID
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
Ext4CacheExtents (
|
Ext4CacheExtents (
|
||||||
IN EXT4_FILE *File,
|
IN EXT4_FILE *File,
|
||||||
IN CONST EXT4_EXTENT *Extents,
|
IN CONST EXT4_EXTENT *Extents,
|
||||||
@ -80,13 +83,15 @@ Ext4GetInoExtentHeader (
|
|||||||
/**
|
/**
|
||||||
Checks if an extent header is valid.
|
Checks if an extent header is valid.
|
||||||
@param[in] Header Pointer to the EXT4_EXTENT_HEADER structure.
|
@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.
|
@return TRUE if valid, FALSE if not.
|
||||||
**/
|
**/
|
||||||
STATIC
|
STATIC
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
Ext4ExtentHeaderValid (
|
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) {
|
if (Header->eh_depth > EXT4_EXTENT_TREE_MAX_DEPTH) {
|
||||||
@ -99,6 +104,18 @@ Ext4ExtentHeaderValid (
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: We do not need to check eh_entries here, as the next branch makes sure max >= entries
|
||||||
|
if (Header->eh_max > MaxEntries) {
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_ERROR,
|
||||||
|
"[ext4] Invalid extent header max entries (%u eh_max, "
|
||||||
|
"theoretical max is %u) (larger than permitted)\n",
|
||||||
|
Header->eh_max,
|
||||||
|
MaxEntries
|
||||||
|
));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (Header->eh_max < Header->eh_entries) {
|
if (Header->eh_max < Header->eh_entries) {
|
||||||
DEBUG ((
|
DEBUG ((
|
||||||
DEBUG_ERROR,
|
DEBUG_ERROR,
|
||||||
@ -212,6 +229,9 @@ Ext4ExtentIdxLeafBlock (
|
|||||||
return LShiftU64 (Index->ei_leaf_hi, 32) | Index->ei_leaf_lo;
|
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.
|
Retrieves an extent from an EXT4 inode.
|
||||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||||
@ -219,7 +239,7 @@ Ext4ExtentIdxLeafBlock (
|
|||||||
@param[in] LogicalBlock Block number which the returned extent must cover.
|
@param[in] LogicalBlock Block number which the returned extent must cover.
|
||||||
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
||||||
|
|
||||||
@retval EFI_SUCCESS Retrieval was succesful.
|
@retval EFI_SUCCESS Retrieval was successful.
|
||||||
@retval EFI_NO_MAPPING Block has no mapping.
|
@retval EFI_NO_MAPPING Block has no mapping.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -237,6 +257,8 @@ Ext4GetExtent (
|
|||||||
EXT4_EXTENT_HEADER *ExtHeader;
|
EXT4_EXTENT_HEADER *ExtHeader;
|
||||||
EXT4_EXTENT_INDEX *Index;
|
EXT4_EXTENT_INDEX *Index;
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
UINT16 MaxExtentsPerNode;
|
||||||
|
EXT4_BLOCK_NR BlockNumber;
|
||||||
|
|
||||||
Inode = File->Inode;
|
Inode = File->Inode;
|
||||||
Ext = NULL;
|
Ext = NULL;
|
||||||
@ -264,7 +286,13 @@ Ext4GetExtent (
|
|||||||
Status = Ext4GetBlocks (Partition, File, (UINT32)LogicalBlock, Extent);
|
Status = Ext4GetBlocks (Partition, File, (UINT32)LogicalBlock, Extent);
|
||||||
|
|
||||||
if (!EFI_ERROR (Status)) {
|
if (!EFI_ERROR (Status)) {
|
||||||
Ext4CacheExtents (File, Extent, 1);
|
Status = Ext4CacheExtents (File, Extent, 1);
|
||||||
|
|
||||||
|
if (EFI_ERROR (Status) && (Status != EFI_OUT_OF_RESOURCES)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
@ -274,12 +302,17 @@ Ext4GetExtent (
|
|||||||
|
|
||||||
ExtHeader = Ext4GetInoExtentHeader (Inode);
|
ExtHeader = Ext4GetInoExtentHeader (Inode);
|
||||||
|
|
||||||
if (!Ext4ExtentHeaderValid (ExtHeader)) {
|
if (!Ext4ExtentHeaderValid (ExtHeader, EXT4_NR_INLINE_EXTENTS)) {
|
||||||
return EFI_VOLUME_CORRUPTED;
|
return EFI_VOLUME_CORRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentDepth = ExtHeader->eh_depth;
|
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 = (UINT16)((Partition->BlockSize / sizeof (EXT4_EXTENT)) - 1);
|
||||||
|
|
||||||
while (ExtHeader->eh_depth != 0) {
|
while (ExtHeader->eh_depth != 0) {
|
||||||
CurrentDepth--;
|
CurrentDepth--;
|
||||||
// While depth != 0, we're traversing the tree itself and not any leaves
|
// While depth != 0, we're traversing the tree itself and not any leaves
|
||||||
@ -289,6 +322,16 @@ Ext4GetExtent (
|
|||||||
// (see FreeBSD).
|
// (see FreeBSD).
|
||||||
|
|
||||||
Index = Ext4BinsearchExtentIndex (ExtHeader, LogicalBlock);
|
Index = Ext4BinsearchExtentIndex (ExtHeader, LogicalBlock);
|
||||||
|
BlockNumber = Ext4ExtentIdxLeafBlock (Index);
|
||||||
|
|
||||||
|
// Check that block isn't file hole
|
||||||
|
if (BlockNumber == EXT4_BLOCK_FILE_HOLE) {
|
||||||
|
if (Buffer != NULL) {
|
||||||
|
FreePool (Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_VOLUME_CORRUPTED;
|
||||||
|
}
|
||||||
|
|
||||||
if (Buffer == NULL) {
|
if (Buffer == NULL) {
|
||||||
Buffer = AllocatePool (Partition->BlockSize);
|
Buffer = AllocatePool (Partition->BlockSize);
|
||||||
@ -299,7 +342,7 @@ Ext4GetExtent (
|
|||||||
|
|
||||||
// Read the leaf block onto the previously-allocated buffer.
|
// Read the leaf block onto the previously-allocated buffer.
|
||||||
|
|
||||||
Status = Ext4ReadBlocks (Partition, Buffer, 1, Ext4ExtentIdxLeafBlock (Index));
|
Status = Ext4ReadBlocks (Partition, Buffer, 1, BlockNumber);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
FreePool (Buffer);
|
FreePool (Buffer);
|
||||||
return Status;
|
return Status;
|
||||||
@ -307,7 +350,7 @@ Ext4GetExtent (
|
|||||||
|
|
||||||
ExtHeader = Buffer;
|
ExtHeader = Buffer;
|
||||||
|
|
||||||
if (!Ext4ExtentHeaderValid (ExtHeader)) {
|
if (!Ext4ExtentHeaderValid (ExtHeader, MaxExtentsPerNode)) {
|
||||||
FreePool (Buffer);
|
FreePool (Buffer);
|
||||||
return EFI_VOLUME_CORRUPTED;
|
return EFI_VOLUME_CORRUPTED;
|
||||||
}
|
}
|
||||||
@ -329,7 +372,15 @@ Ext4GetExtent (
|
|||||||
* by linux (and possibly other systems) is quite fancy and usually it results in a small number of extents.
|
* by linux (and possibly other systems) is quite fancy and usually it results in a small number of extents.
|
||||||
* Therefore, we shouldn't have any memory issues.
|
* Therefore, we shouldn't have any memory issues.
|
||||||
**/
|
**/
|
||||||
Ext4CacheExtents (File, (EXT4_EXTENT *)(ExtHeader + 1), ExtHeader->eh_entries);
|
Status = Ext4CacheExtents (File, (EXT4_EXTENT *)(ExtHeader + 1), ExtHeader->eh_entries);
|
||||||
|
|
||||||
|
if (EFI_ERROR (Status) && (Status != EFI_OUT_OF_RESOURCES)) {
|
||||||
|
if (Buffer != NULL) {
|
||||||
|
FreePool (Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
Ext = Ext4BinsearchExtentExt (ExtHeader, LogicalBlock);
|
Ext = Ext4BinsearchExtentExt (ExtHeader, LogicalBlock);
|
||||||
|
|
||||||
@ -485,8 +536,11 @@ Ext4FreeExtentsMap (
|
|||||||
@param[in] File Pointer to the open file.
|
@param[in] File Pointer to the open file.
|
||||||
@param[in] Extents Pointer to an array of extents.
|
@param[in] Extents Pointer to an array of extents.
|
||||||
@param[in] NumberExtents Length of the array.
|
@param[in] NumberExtents Length of the array.
|
||||||
|
|
||||||
|
@return Result of the caching
|
||||||
**/
|
**/
|
||||||
VOID
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
Ext4CacheExtents (
|
Ext4CacheExtents (
|
||||||
IN EXT4_FILE *File,
|
IN EXT4_FILE *File,
|
||||||
IN CONST EXT4_EXTENT *Extents,
|
IN CONST EXT4_EXTENT *Extents,
|
||||||
@ -502,10 +556,15 @@ Ext4CacheExtents (
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
for (Idx = 0; Idx < NumberExtents; Idx++, Extents++) {
|
for (Idx = 0; Idx < NumberExtents; Idx++, Extents++) {
|
||||||
|
if (Extents->ee_len == 0) {
|
||||||
|
// 0-sized extent, must be corruption
|
||||||
|
return EFI_VOLUME_CORRUPTED;
|
||||||
|
}
|
||||||
|
|
||||||
Extent = AllocatePool (sizeof (EXT4_EXTENT));
|
Extent = AllocatePool (sizeof (EXT4_EXTENT));
|
||||||
|
|
||||||
if (Extent == NULL) {
|
if (Extent == NULL) {
|
||||||
return;
|
return EFI_OUT_OF_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyMem (Extent, Extents, sizeof (EXT4_EXTENT));
|
CopyMem (Extent, Extents, sizeof (EXT4_EXTENT));
|
||||||
@ -519,9 +578,11 @@ Ext4CacheExtents (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -615,7 +676,7 @@ Ext4GetExtentLength (
|
|||||||
IN CONST EXT4_EXTENT *Extent
|
IN CONST EXT4_EXTENT *Extent
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// If it's an unintialized extent, the true length is ee_len - 2^15
|
// If it's an uninitialized extent, the true length is ee_len - 2^15
|
||||||
if (EXT4_EXTENT_IS_UNINITIALIZED (Extent)) {
|
if (EXT4_EXTENT_IS_UNINITIALIZED (Extent)) {
|
||||||
return Extent->ee_len - EXT4_EXTENT_MAX_INITIALIZED;
|
return Extent->ee_len - EXT4_EXTENT_MAX_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ Ext4IsLastPathSegment (
|
|||||||
@param[in out] File Pointer to the file we're opening.
|
@param[in out] File Pointer to the file we're opening.
|
||||||
@param[in] OpenMode Mode in which to open the file.
|
@param[in] OpenMode Mode in which to open the file.
|
||||||
|
|
||||||
@return True if the open was succesful, false if we don't have
|
@return True if the open was successful, false if we don't have
|
||||||
enough permissions.
|
enough permissions.
|
||||||
**/
|
**/
|
||||||
STATIC
|
STATIC
|
||||||
@ -207,6 +207,11 @@ Ext4OpenInternal (
|
|||||||
Level = 0;
|
Level = 0;
|
||||||
|
|
||||||
DEBUG ((DEBUG_FS, "[ext4] Ext4OpenInternal %s\n", FileName));
|
DEBUG ((DEBUG_FS, "[ext4] Ext4OpenInternal %s\n", FileName));
|
||||||
|
|
||||||
|
if (!Ext4FileIsDir (Current)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
// If the path starts with a backslash, we treat the root directory as the base directory
|
// If the path starts with a backslash, we treat the root directory as the base directory
|
||||||
if (FileName[0] == L'\\') {
|
if (FileName[0] == L'\\') {
|
||||||
FileName++;
|
FileName++;
|
||||||
@ -219,6 +224,10 @@ Ext4OpenInternal (
|
|||||||
return EFI_ACCESS_DENIED;
|
return EFI_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Ext4FileIsDir (Current)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
// Discard leading path separators
|
// Discard leading path separators
|
||||||
while (FileName[0] == L'\\') {
|
while (FileName[0] == L'\\') {
|
||||||
FileName++;
|
FileName++;
|
||||||
@ -242,10 +251,6 @@ Ext4OpenInternal (
|
|||||||
|
|
||||||
DEBUG ((DEBUG_FS, "[ext4] Opening %s\n", PathSegment));
|
DEBUG ((DEBUG_FS, "[ext4] Opening %s\n", PathSegment));
|
||||||
|
|
||||||
if (!Ext4FileIsDir (Current)) {
|
|
||||||
return EFI_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Ext4IsLastPathSegment (FileName)) {
|
if (!Ext4IsLastPathSegment (FileName)) {
|
||||||
if (!Ext4DirCanLookup (Current)) {
|
if (!Ext4DirCanLookup (Current)) {
|
||||||
return EFI_ACCESS_DENIED;
|
return EFI_ACCESS_DENIED;
|
||||||
@ -715,6 +720,10 @@ Ext4GetVolumeName (
|
|||||||
VolNameLength = StrLen (VolumeName);
|
VolNameLength = StrLen (VolumeName);
|
||||||
} else {
|
} else {
|
||||||
VolumeName = AllocateZeroPool (sizeof (CHAR16));
|
VolumeName = AllocateZeroPool (sizeof (CHAR16));
|
||||||
|
if (VolumeName == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
VolNameLength = 0;
|
VolNameLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -781,7 +790,9 @@ Ext4GetFilesystemInfo (
|
|||||||
Info->VolumeSize = MultU64x32 (TotalBlocks, Part->BlockSize);
|
Info->VolumeSize = MultU64x32 (TotalBlocks, Part->BlockSize);
|
||||||
Info->FreeSpace = MultU64x32 (FreeBlocks, Part->BlockSize);
|
Info->FreeSpace = MultU64x32 (FreeBlocks, Part->BlockSize);
|
||||||
|
|
||||||
StrCpyS (Info->VolumeLabel, VolNameLength + 1, VolumeName);
|
Status = StrCpyS (Info->VolumeLabel, VolNameLength + 1, VolumeName);
|
||||||
|
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
FreePool (VolumeName);
|
FreePool (VolumeName);
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ Ext4CalculateInodeChecksum (
|
|||||||
@param[out] Buffer Pointer to the buffer.
|
@param[out] Buffer Pointer to the buffer.
|
||||||
@param[in] Offset Offset of the read.
|
@param[in] Offset Offset of the read.
|
||||||
@param[in out] Length Pointer to the length of the buffer, in bytes.
|
@param[in out] Length Pointer to the length of the buffer, in bytes.
|
||||||
After a succesful read, it's updated to the number of read bytes.
|
After a successful read, it's updated to the number of read bytes.
|
||||||
|
|
||||||
@return Status of the read operation.
|
@return Status of the read operation.
|
||||||
**/
|
**/
|
||||||
@ -152,7 +152,7 @@ Ext4Read (
|
|||||||
} else {
|
} else {
|
||||||
// Uninitialized extents behave exactly the same as file holes, except they have
|
// Uninitialized extents behave exactly the same as file holes, except they have
|
||||||
// blocks already allocated to them.
|
// blocks already allocated to them.
|
||||||
HoleLen = (Ext4GetExtentLength (&Extent) * Partition->BlockSize) - HoleOff;
|
HoleLen = MultU64x32 (Ext4GetExtentLength (&Extent), Partition->BlockSize) - HoleOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
WasRead = HoleLen > RemainingRead ? RemainingRead : (UINTN)HoleLen;
|
WasRead = HoleLen > RemainingRead ? RemainingRead : (UINTN)HoleLen;
|
||||||
@ -166,7 +166,7 @@ Ext4Read (
|
|||||||
Partition->BlockSize
|
Partition->BlockSize
|
||||||
);
|
);
|
||||||
ExtentLengthBytes = Extent.ee_len * Partition->BlockSize;
|
ExtentLengthBytes = Extent.ee_len * Partition->BlockSize;
|
||||||
ExtentLogicalBytes = (UINT64)Extent.ee_block * Partition->BlockSize;
|
ExtentLogicalBytes = MultU64x32 ((UINT64)Extent.ee_block, Partition->BlockSize);
|
||||||
ExtentOffset = CurrentSeek - ExtentLogicalBytes;
|
ExtentOffset = CurrentSeek - ExtentLogicalBytes;
|
||||||
ExtentMayRead = (UINTN)(ExtentLengthBytes - ExtentOffset);
|
ExtentMayRead = (UINTN)(ExtentLengthBytes - ExtentOffset);
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ Ext4AllocateInode (
|
|||||||
|
|
||||||
Inode = AllocateZeroPool (InodeSize);
|
Inode = AllocateZeroPool (InodeSize);
|
||||||
|
|
||||||
if (!Inode) {
|
if (Inode == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Superblock managing routines
|
Superblock managing 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
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ STATIC CONST UINT32 gSupportedIncompatFeat =
|
|||||||
EXT4_FEATURE_INCOMPAT_64BIT | EXT4_FEATURE_INCOMPAT_DIRDATA |
|
EXT4_FEATURE_INCOMPAT_64BIT | EXT4_FEATURE_INCOMPAT_DIRDATA |
|
||||||
EXT4_FEATURE_INCOMPAT_FLEX_BG | EXT4_FEATURE_INCOMPAT_FILETYPE |
|
EXT4_FEATURE_INCOMPAT_FLEX_BG | EXT4_FEATURE_INCOMPAT_FILETYPE |
|
||||||
EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_LARGEDIR |
|
EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_LARGEDIR |
|
||||||
EXT4_FEATURE_INCOMPAT_MMP | EXT4_FEATURE_INCOMPAT_RECOVER;
|
EXT4_FEATURE_INCOMPAT_MMP | EXT4_FEATURE_INCOMPAT_RECOVER | EXT4_FEATURE_INCOMPAT_CSUM_SEED;
|
||||||
|
|
||||||
// Future features that may be nice additions in the future:
|
// Future features that may be nice additions in the future:
|
||||||
// 1) Btree support: Required for write support and would speed up lookups in large directories.
|
// 1) Btree support: Required for write support and would speed up lookups in large directories.
|
||||||
@ -151,7 +151,7 @@ Ext4VerifySuperblockChecksum (
|
|||||||
Opens and parses the superblock.
|
Opens and parses the superblock.
|
||||||
|
|
||||||
@param[out] Partition Partition structure to fill with filesystem details.
|
@param[out] Partition Partition structure to fill with filesystem details.
|
||||||
@retval EFI_SUCCESS Parsing was succesful and the partition is a
|
@retval EFI_SUCCESS Parsing was successful and the partition is a
|
||||||
valid ext4 partition.
|
valid ext4 partition.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -203,7 +203,7 @@ Ext4OpenSuperblock (
|
|||||||
|
|
||||||
// Now, check for the feature set of the filesystem
|
// Now, check for the feature set of the filesystem
|
||||||
// It's essential to check for this to avoid filesystem corruption and to avoid
|
// It's essential to check for this to avoid filesystem corruption and to avoid
|
||||||
// accidentally opening an ext2/3/4 filesystem we don't understand, which would be disasterous.
|
// accidentally opening an ext2/3/4 filesystem we don't understand, which would be disastrous.
|
||||||
|
|
||||||
if (Partition->FeaturesIncompat & ~gSupportedIncompatFeat) {
|
if (Partition->FeaturesIncompat & ~gSupportedIncompatFeat) {
|
||||||
DEBUG ((
|
DEBUG ((
|
||||||
@ -220,13 +220,11 @@ Ext4OpenSuperblock (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// At the time of writing, it's the only supported checksum.
|
// At the time of writing, it's the only supported checksum.
|
||||||
if (Partition->FeaturesCompat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM &&
|
if (EXT4_HAS_METADATA_CSUM (Partition) && (Sb->s_checksum_type != EXT4_CHECKSUM_CRC32C)) {
|
||||||
(Sb->s_checksum_type != EXT4_CHECKSUM_CRC32C))
|
|
||||||
{
|
|
||||||
return EFI_UNSUPPORTED;
|
return EFI_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Partition->FeaturesIncompat & EXT4_FEATURE_INCOMPAT_CSUM_SEED) != 0) {
|
if (EXT4_HAS_INCOMPAT (Partition, EXT4_FEATURE_INCOMPAT_CSUM_SEED)) {
|
||||||
Partition->InitialSeed = Sb->s_checksum_seed;
|
Partition->InitialSeed = Sb->s_checksum_seed;
|
||||||
} else {
|
} else {
|
||||||
Partition->InitialSeed = Ext4CalculateChecksum (Partition, Sb->s_uuid, 16, ~0U);
|
Partition->InitialSeed = Ext4CalculateChecksum (Partition, Sb->s_uuid, 16, ~0U);
|
||||||
@ -245,6 +243,16 @@ Ext4OpenSuperblock (
|
|||||||
|
|
||||||
DEBUG ((DEBUG_FS, "Read only = %u\n", Partition->ReadOnly));
|
DEBUG ((DEBUG_FS, "Read only = %u\n", Partition->ReadOnly));
|
||||||
|
|
||||||
|
if (Sb->s_inodes_per_group == 0) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "[ext4] Inodes per group can not be zero\n"));
|
||||||
|
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);
|
Partition->BlockSize = (UINT32)LShiftU64 (1024, Sb->s_log_block_size);
|
||||||
|
|
||||||
// The size of a block group can also be calculated as 8 * Partition->BlockSize
|
// The size of a block group can also be calculated as 8 * Partition->BlockSize
|
||||||
@ -312,7 +320,7 @@ Ext4OpenSuperblock (
|
|||||||
return EFI_OUT_OF_RESOURCES;
|
return EFI_OUT_OF_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that the cast below is completely safe, because EXT4_FILE is a specialisation of EFI_FILE_PROTOCOL
|
// Note that the cast below is completely safe, because EXT4_FILE is a specialization of EFI_FILE_PROTOCOL
|
||||||
Status = Ext4OpenVolume (&Partition->Interface, (EFI_FILE_PROTOCOL **)&Partition->Root);
|
Status = Ext4OpenVolume (&Partition->Interface, (EFI_FILE_PROTOCOL **)&Partition->Root);
|
||||||
|
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** @file
|
/** @file
|
||||||
Symbolic links routines
|
Symbolic links routines
|
||||||
|
|
||||||
Copyright (c) 2022 Savva Mitrofanov All rights reserved.
|
Copyright (c) 2022-2023 Savva Mitrofanov All rights reserved.
|
||||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@ -155,19 +155,20 @@ Ext4ReadSlowSymlink (
|
|||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Add null-terminator
|
|
||||||
//
|
|
||||||
SymlinkTmp[SymlinkSizeTmp] = '\0';
|
|
||||||
|
|
||||||
if (SymlinkSizeTmp != ReadSize) {
|
if (SymlinkSizeTmp != ReadSize) {
|
||||||
DEBUG ((
|
DEBUG ((
|
||||||
DEBUG_FS,
|
DEBUG_FS,
|
||||||
"[ext4] Error! The size of the read block doesn't match the value from the inode!\n"
|
"[ext4] Error! The size of the read block doesn't match the value from the inode!\n"
|
||||||
));
|
));
|
||||||
|
FreePool (SymlinkTmp);
|
||||||
return EFI_VOLUME_CORRUPTED;
|
return EFI_VOLUME_CORRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add null-terminator
|
||||||
|
//
|
||||||
|
SymlinkTmp[ReadSize] = '\0';
|
||||||
|
|
||||||
*AsciiSymlinkSize = SymlinkAllocateSize;
|
*AsciiSymlinkSize = SymlinkAllocateSize;
|
||||||
*AsciiSymlink = SymlinkTmp;
|
*AsciiSymlink = SymlinkTmp;
|
||||||
|
|
||||||
@ -201,7 +202,7 @@ Ext4ReadSymlink (
|
|||||||
CHAR16 *Needle;
|
CHAR16 *Needle;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assume that we alread read Inode via Ext4ReadInode
|
// Assume that we already read Inode via Ext4ReadInode
|
||||||
// Skip reading, just check encryption flag
|
// Skip reading, just check encryption flag
|
||||||
//
|
//
|
||||||
if ((File->Inode->i_flags & EXT4_ENCRYPT_FL) != 0) {
|
if ((File->Inode->i_flags & EXT4_ENCRYPT_FL) != 0) {
|
||||||
@ -242,7 +243,6 @@ Ext4ReadSymlink (
|
|||||||
Status
|
Status
|
||||||
));
|
));
|
||||||
FreePool (Symlink16Tmp);
|
FreePool (Symlink16Tmp);
|
||||||
FreePool (SymlinkTmp);
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user