Handle on-disk format and volume structures in UDF/ECMA-167 file systems.\r
\r
Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials are licensed and made available\r
under the terms and conditions of the BSD License which accompanies this\r
/**\r
Return logical sector number of a given Long Allocation Descriptor.\r
\r
- @param[in] Volume Volume information pointer.\r
- @param[in] LongAd Long Allocation Descriptor pointer.\r
+ @param[in] Volume Volume information pointer.\r
+ @param[in] LongAd Long Allocation Descriptor pointer.\r
+ @param[out] Lsn Logical sector number pointer.\r
\r
- @return The logical sector number of a given Long Allocation Descriptor.\r
+ @retval EFI_SUCCESS Logical sector number successfully returned.\r
+ @retval EFI_UNSUPPORTED Logical sector number is not returned due to\r
+ unrecognized format.\r
\r
**/\r
-UINT64\r
+EFI_STATUS\r
GetLongAdLsn (\r
- IN UDF_VOLUME_INFO *Volume,\r
- IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd\r
+ IN UDF_VOLUME_INFO *Volume,\r
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd,\r
+ OUT UINT64 *Lsn\r
)\r
{\r
UDF_PARTITION_DESCRIPTOR *PartitionDesc;\r
\r
PartitionDesc = GetPdFromLongAd (Volume, LongAd);\r
- ASSERT (PartitionDesc != NULL);\r
+ if (PartitionDesc == NULL) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",\r
+ __FUNCTION__\r
+ ));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
\r
- return (UINT64)PartitionDesc->PartitionStartingLocation -\r
- Volume->MainVdsStartLocation +\r
- LongAd->ExtentLocation.LogicalBlockNumber;\r
+ *Lsn = (UINT64)PartitionDesc->PartitionStartingLocation -\r
+ Volume->MainVdsStartLocation +\r
+ LongAd->ExtentLocation.LogicalBlockNumber;\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
UDF_DESCRIPTOR_TAG *DescriptorTag;\r
\r
LogicalVolDesc = &Volume->LogicalVolDesc;\r
- Lsn = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse);\r
+ Status = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse, &Lsn);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
//\r
// As per UDF 2.60 specification:\r
*NewFileIdentifierDesc =\r
(UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool (\r
(UINTN) GetFidDescriptorLength (FileIdentifierDesc), FileIdentifierDesc);\r
-\r
- ASSERT (*NewFileIdentifierDesc != NULL);\r
}\r
\r
/**\r
)\r
{\r
*NewFileEntry = AllocateCopyPool (Volume->FileEntrySize, FileEntry);\r
-\r
- ASSERT (*NewFileEntry != NULL);\r
}\r
\r
/**\r
);\r
}\r
\r
+ //\r
+ // Code should never reach here.\r
+ //\r
+ ASSERT (FALSE);\r
return EFI_DEVICE_ERROR;\r
}\r
\r
@param[in] Volume Volume information pointer.\r
@param[in] ParentIcb Long Allocation Descriptor pointer.\r
@param[in] Ad Allocation Descriptor pointer.\r
+ @param[out] Lsn Logical sector number pointer.\r
\r
- @return The logical sector number of the given Allocation Descriptor.\r
+ @retval EFI_SUCCESS Logical sector number of the given Allocation\r
+ Descriptor successfully returned.\r
+ @retval EFI_UNSUPPORTED Logical sector number of the given Allocation\r
+ Descriptor is not returned due to unrecognized\r
+ format.\r
\r
**/\r
-UINT64\r
+EFI_STATUS\r
GetAllocationDescriptorLsn (\r
- IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
- IN UDF_VOLUME_INFO *Volume,\r
- IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
- IN VOID *Ad\r
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
+ IN UDF_VOLUME_INFO *Volume,\r
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
+ IN VOID *Ad,\r
+ OUT UINT64 *Lsn\r
)\r
{\r
UDF_PARTITION_DESCRIPTOR *PartitionDesc;\r
\r
if (RecordingFlags == LongAdsSequence) {\r
- return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad);\r
+ return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad, Lsn);\r
} else if (RecordingFlags == ShortAdsSequence) {\r
PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);\r
- ASSERT (PartitionDesc != NULL);\r
+ if (PartitionDesc == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
\r
- return GetShortAdLsn (\r
- Volume,\r
- PartitionDesc,\r
- (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad\r
- );\r
+ *Lsn = GetShortAdLsn (\r
+ Volume,\r
+ PartitionDesc,\r
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad\r
+ );\r
+ return EFI_SUCCESS;\r
}\r
\r
- return 0;\r
+ //\r
+ // Code should never reach here.\r
+ //\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
}\r
\r
/**\r
UDF_DESCRIPTOR_TAG *DescriptorTag;\r
\r
ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
- Lsn = GetAllocationDescriptorLsn (RecordingFlags,\r
+ Status = GetAllocationDescriptorLsn (RecordingFlags,\r
Volume,\r
ParentIcb,\r
- Ad);\r
+ Ad,\r
+ &Lsn);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
Data = AllocatePool (ExtentLength);\r
if (Data == NULL) {\r
\r
ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
\r
- Lsn = GetAllocationDescriptorLsn (RecordingFlags,\r
- Volume,\r
- ParentIcb,\r
- Ad);\r
+ Status = GetAllocationDescriptorLsn (RecordingFlags,\r
+ Volume,\r
+ ParentIcb,\r
+ Ad,\r
+ &Lsn);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
\r
switch (ReadFileInfo->Flags) {\r
case ReadFileGetFileSize:\r
}\r
\r
DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);\r
+ if (File->FileEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);\r
+ if (File->FileIdentifierDesc == NULL) {\r
+ FreePool (File->FileEntry);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
\r
return EFI_SUCCESS;\r
}\r
\r
break;\r
}\r
+ //\r
+ // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is\r
+ // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code\r
+ // reaches here, 'FileIdentifierDesc' must be not NULL.\r
+ //\r
+ // The ASSERT here is for addressing a false positive NULL pointer\r
+ // dereference issue raised from static analysis.\r
+ //\r
+ ASSERT (FileIdentifierDesc != NULL);\r
\r
if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {\r
//\r
break;\r
}\r
} else {\r
- Status = GetFileNameFromFid (FileIdentifierDesc, FoundFileName);\r
+ Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);\r
if (EFI_ERROR (Status)) {\r
break;\r
}\r
UINT64 Lsn;\r
UINT32 LogicalBlockSize;\r
UDF_DESCRIPTOR_TAG *DescriptorTag;\r
+ VOID *ReadBuffer;\r
+\r
+ Status = GetLongAdLsn (Volume, Icb, &Lsn);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
- Lsn = GetLongAdLsn (Volume, Icb);\r
LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
\r
- *FileEntry = AllocateZeroPool (Volume->FileEntrySize);\r
- if (*FileEntry == NULL) {\r
+ ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);\r
+ if (ReadBuffer == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
BlockIo->Media->MediaId,\r
MultU64x32 (Lsn, LogicalBlockSize),\r
Volume->FileEntrySize,\r
- *FileEntry\r
+ ReadBuffer\r
);\r
if (EFI_ERROR (Status)) {\r
goto Error_Read_Disk_Blk;\r
}\r
\r
- DescriptorTag = *FileEntry;\r
+ DescriptorTag = ReadBuffer;\r
\r
//\r
// Check if the read extent contains a valid Tag Identifier for the expected\r
goto Error_Invalid_Fe;\r
}\r
\r
+ *FileEntry = ReadBuffer;\r
return EFI_SUCCESS;\r
\r
Error_Invalid_Fe:\r
Error_Read_Disk_Blk:\r
- FreePool (*FileEntry);\r
+ FreePool (ReadBuffer);\r
\r
return Status;\r
}\r
while (*FilePath != L'\0') {\r
FileNamePointer = FileName;\r
while (*FilePath != L'\0' && *FilePath != L'\\') {\r
+ if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=\r
+ (ARRAY_SIZE (FileName) - 1)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
*FileNamePointer++ = *FilePath++;\r
}\r
\r
// We've already a file pointer (Root) for the root directory. Duplicate\r
// its FE/EFE and FID descriptors.\r
//\r
- DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);\r
- DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);\r
Status = EFI_SUCCESS;\r
+ DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);\r
+ if (File->FileEntry == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ //\r
+ // File->FileEntry is not NULL.\r
+ //\r
+ DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);\r
+ if (File->FileIdentifierDesc == NULL) {\r
+ FreePool (File->FileEntry);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
}\r
} else {\r
//\r
} while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);\r
\r
DuplicateFid (FileIdentifierDesc, FoundFid);\r
+ if (*FoundFid == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
\r
return EFI_SUCCESS;\r
}\r
Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
Descriptor on an UDF volume.\r
\r
+ @attention This is boundary function that may receive untrusted input.\r
+ @attention The input is from FileSystem.\r
+\r
+ The File Identifier Descriptor is external input, so this routine will do\r
+ basic validation for File Identifier Descriptor and report status.\r
+\r
@param[in] FileIdentifierDesc File Identifier Descriptor pointer.\r
+ @param[in] CharMax The maximum number of FileName Unicode char,\r
+ including terminating null char.\r
@param[out] FileName Decoded filename.\r
\r
@retval EFI_SUCCESS Filename decoded and read.\r
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the\r
+ decoded filename.\r
**/\r
EFI_STATUS\r
GetFileNameFromFid (\r
IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,\r
+ IN UINTN CharMax,\r
OUT CHAR16 *FileName\r
)\r
{\r
- UINT8 *OstaCompressed;\r
- UINT8 CompressionId;\r
- UINT8 Length;\r
- UINTN Index;\r
+ UINT8 *OstaCompressed;\r
+ UINT8 CompressionId;\r
+ UINT8 Length;\r
+ UINTN Index;\r
+ CHAR16 *FileNameBak;\r
+\r
+ if (CharMax == 0) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
\r
OstaCompressed =\r
(UINT8 *)(\r
return EFI_VOLUME_CORRUPTED;\r
}\r
\r
+ FileNameBak = FileName;\r
+\r
//\r
// Decode filename.\r
//\r
Length = FileIdentifierDesc->LengthOfFileIdentifier;\r
+ if (CompressionId == 16) {\r
+ if (((UINTN)Length >> 1) > CharMax) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ } else {\r
+ if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ }\r
+\r
for (Index = 1; Index < Length; Index++) {\r
if (CompressionId == 16) {\r
*FileName = OstaCompressed[Index++] << 8;\r
FileName++;\r
}\r
\r
- *FileName = L'\0';\r
+ Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);\r
+ if (Index > CharMax - 1) {\r
+ Index = CharMax - 1;\r
+ }\r
+ FileNameBak[Index] = L'\0';\r
\r
return EFI_SUCCESS;\r
}\r
/**\r
Resolve a symlink file on an UDF volume.\r
\r
+ @attention This is boundary function that may receive untrusted input.\r
+ @attention The input is from FileSystem.\r
+\r
+ The Path Component is external input, so this routine will do basic\r
+ validation for Path Component and report status.\r
+\r
@param[in] BlockIo BlockIo interface.\r
@param[in] DiskIo DiskIo interface.\r
@param[in] Volume UDF volume information structure.\r
// "." (current file). Duplicate both FE/EFE and FID of this file.\r
//\r
DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);\r
+ if (File->FileEntry == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error_Find_File;\r
+ }\r
+\r
DuplicateFid (PreviousFile.FileIdentifierDesc,\r
&File->FileIdentifierDesc);\r
+ if (File->FileIdentifierDesc == NULL) {\r
+ FreePool (File->FileEntry);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error_Find_File;\r
+ }\r
goto Next_Path_Component;\r
case 5:\r
//\r
Index) << 8;\r
Index++;\r
} else {\r
+ if (Index > ARRAY_SIZE (FileName)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
*Char = 0;\r
}\r
\r
Char++;\r
}\r
\r
- *Char = L'\0';\r
+ Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);\r
+ if (Index > ARRAY_SIZE (FileName) - 1) {\r
+ Index = ARRAY_SIZE (FileName) - 1;\r
+ }\r
+ FileName[Index] = L'\0';\r
break;\r
}\r
\r