]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdeModulePkg/UdfDxe: Refine boundary checks for file/path name string
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / UdfDxe / FileSystemOperations.c
index 8b58cc9eb16df6e1a10a00f2edb2290cf0070094..b3ac673cac4952518d65cbe6635566abc2a605f4 100644 (file)
@@ -2,6 +2,7 @@
   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
   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
   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
@@ -271,26 +272,39 @@ GetPdFromLongAd (
 /**\r
   Return logical sector number of a given Long Allocation Descriptor.\r
 \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
 \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
 \r
 **/\r
-UINT64\r
+EFI_STATUS\r
 GetLongAdLsn (\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
   )\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
 \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
 }\r
 \r
 /**\r
@@ -342,7 +356,10 @@ FindFileSetDescriptor (
   UDF_DESCRIPTOR_TAG             *DescriptorTag;\r
 \r
   LogicalVolDesc = &Volume->LogicalVolDesc;\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
 \r
   //\r
   // As per UDF 2.60 specification:\r
@@ -722,6 +739,10 @@ GetAllocationDescriptor (
       );\r
   }\r
 \r
       );\r
   }\r
 \r
+  //\r
+  // Code should never reach here.\r
+  //\r
+  ASSERT (FALSE);\r
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
@@ -732,34 +753,47 @@ GetAllocationDescriptor (
   @param[in]  Volume              Volume information pointer.\r
   @param[in]  ParentIcb           Long Allocation Descriptor pointer.\r
   @param[in]  Ad                  Allocation Descriptor pointer.\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
 \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
 \r
 **/\r
-UINT64\r
+EFI_STATUS\r
 GetAllocationDescriptorLsn (\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
   )\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
   } else if (RecordingFlags == ShortAdsSequence) {\r
     PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);\r
-    ASSERT (PartitionDesc != NULL);\r
+    if (PartitionDesc == NULL) {\r
+      return EFI_UNSUPPORTED;\r
+    }\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
   }\r
 \r
-  return 0;\r
+  //\r
+  // Code should never reach here.\r
+  //\r
+  ASSERT (FALSE);\r
+  return EFI_UNSUPPORTED;\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -804,10 +838,14 @@ GetAedAdsOffset (
   UDF_DESCRIPTOR_TAG                *DescriptorTag;\r
 \r
   ExtentLength  = GET_EXTENT_LENGTH (RecordingFlags, Ad);\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
                                               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
   Data = AllocatePool (ExtentLength);\r
   if (Data == NULL) {\r
@@ -1156,10 +1194,14 @@ ReadFile (
 \r
       ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
 \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
       switch (ReadFileInfo->Flags) {\r
       case ReadFileGetFileSize:\r
@@ -1425,7 +1467,7 @@ InternalFindFile (
         break;\r
       }\r
     } else {\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
       if (EFI_ERROR (Status)) {\r
         break;\r
       }\r
@@ -1630,7 +1672,11 @@ FindFileEntry (
   UDF_DESCRIPTOR_TAG  *DescriptorTag;\r
   VOID                *ReadBuffer;\r
 \r
   UDF_DESCRIPTOR_TAG  *DescriptorTag;\r
   VOID                *ReadBuffer;\r
 \r
-  Lsn               = GetLongAdLsn (Volume, Icb);\r
+  Status = GetLongAdLsn (Volume, Icb, &Lsn);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   LogicalBlockSize  = Volume->LogicalVolDesc.LogicalBlockSize;\r
 \r
   ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);\r
   LogicalBlockSize  = Volume->LogicalVolDesc.LogicalBlockSize;\r
 \r
   ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);\r
@@ -1718,6 +1764,11 @@ FindFile (
   while (*FilePath != L'\0') {\r
     FileNamePointer = FileName;\r
     while (*FilePath != L'\0' && *FilePath != L'\\') {\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
       *FileNamePointer++ = *FilePath++;\r
     }\r
 \r
@@ -1909,22 +1960,38 @@ ReadDirectoryEntry (
   Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
   Descriptor on an UDF volume.\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]   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
   @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
 **/\r
 EFI_STATUS\r
 GetFileNameFromFid (\r
   IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,\r
+  IN   UINTN                           CharMax,\r
   OUT  CHAR16                          *FileName\r
   )\r
 {\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
 \r
   OstaCompressed =\r
     (UINT8 *)(\r
@@ -1937,10 +2004,22 @@ GetFileNameFromFid (
     return EFI_VOLUME_CORRUPTED;\r
   }\r
 \r
     return EFI_VOLUME_CORRUPTED;\r
   }\r
 \r
+  FileNameBak = FileName;\r
+\r
   //\r
   // Decode filename.\r
   //\r
   Length = FileIdentifierDesc->LengthOfFileIdentifier;\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
   for (Index = 1; Index < Length; Index++) {\r
     if (CompressionId == 16) {\r
       *FileName = OstaCompressed[Index++] << 8;\r
@@ -1955,7 +2034,11 @@ GetFileNameFromFid (
     FileName++;\r
   }\r
 \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
   return EFI_SUCCESS;\r
 }\r
@@ -1963,6 +2046,12 @@ GetFileNameFromFid (
 /**\r
   Resolve a symlink file on an UDF volume.\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
   @param[in]   BlockIo        BlockIo interface.\r
   @param[in]   DiskIo         DiskIo interface.\r
   @param[in]   Volume         UDF volume information structure.\r
@@ -2091,6 +2180,9 @@ ResolveSymlink (
                           Index) << 8;\r
           Index++;\r
         } else {\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 = 0;\r
         }\r
 \r
@@ -2101,7 +2193,11 @@ ResolveSymlink (
         Char++;\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
       break;\r
     }\r
 \r