]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdeModulePkg/UdfDxe: Add boundary check for ComponentIdentifier decode
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / UdfDxe / FileSystemOperations.c
index 1400846bf103a765c89065d2695b1422efb02923..359fac0adf6088f9a86605648a44b0a770138c02 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
+  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
@@ -515,15 +516,27 @@ DuplicateFe (
 \r
   NOTE: The FE/EFE can be thought it was an inode.\r
 \r
+  @attention This is boundary function that may receive untrusted input.\r
+  @attention The input is from FileSystem.\r
+\r
+  The (Extended) File Entry is external input, so this routine will do basic\r
+  validation for (Extended) File Entry and report status.\r
+\r
   @param[in]  FileEntryData       (Extended) File Entry pointer.\r
+  @param[in]  FileEntrySize       Size of the (Extended) File Entry specified\r
+                                  by FileEntryData.\r
   @param[out] Data                Buffer contains the raw data of a given\r
                                   (Extended) File Entry.\r
   @param[out] Length              Length of the data in Buffer.\r
 \r
+  @retval EFI_SUCCESS             Raw data and size of the FE/EFE was read.\r
+  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.\r
+\r
 **/\r
-VOID\r
+EFI_STATUS\r
 GetFileEntryData (\r
   IN   VOID    *FileEntryData,\r
+  IN   UINTN   FileEntrySize,\r
   OUT  VOID    **Data,\r
   OUT  UINT64  *Length\r
   )\r
@@ -547,20 +560,40 @@ GetFileEntryData (
     *Data    = (VOID *)((UINT8 *)FileEntry->Data +\r
                         FileEntry->LengthOfExtendedAttributes);\r
   }\r
+\r
+  if ((*Length > FileEntrySize) ||\r
+      ((UINTN)FileEntryData > (UINTN)(*Data)) ||\r
+      ((UINTN)(*Data) - (UINTN)FileEntryData > FileEntrySize - *Length)) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
   Get Allocation Descriptors' data information from a given FE/EFE.\r
 \r
+  @attention This is boundary function that may receive untrusted input.\r
+  @attention The input is from FileSystem.\r
+\r
+  The (Extended) File Entry is external input, so this routine will do basic\r
+  validation for (Extended) File Entry and report status.\r
+\r
   @param[in]  FileEntryData       (Extended) File Entry pointer.\r
+  @param[in]  FileEntrySize       Size of the (Extended) File Entry specified\r
+                                  by FileEntryData.\r
   @param[out] AdsData             Buffer contains the Allocation Descriptors'\r
                                   data from a given FE/EFE.\r
   @param[out] Length              Length of the data in AdsData.\r
 \r
+  @retval EFI_SUCCESS             The data and size of Allocation Descriptors\r
+                                  were read from the FE/EFE.\r
+  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.\r
+\r
 **/\r
-VOID\r
+EFI_STATUS\r
 GetAdsInformation (\r
   IN   VOID    *FileEntryData,\r
+  IN   UINTN   FileEntrySize,\r
   OUT  VOID    **AdsData,\r
   OUT  UINT64  *Length\r
   )\r
@@ -584,6 +617,13 @@ GetAdsInformation (
     *AdsData = (VOID *)((UINT8 *)FileEntry->Data +\r
                         FileEntry->LengthOfExtendedAttributes);\r
   }\r
+\r
+  if ((*Length > FileEntrySize) ||\r
+      ((UINTN)FileEntryData > (UINTN)(*AdsData)) ||\r
+      ((UINTN)(*AdsData) - (UINTN)FileEntryData > FileEntrySize - *Length)) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -738,6 +778,10 @@ GetAllocationDescriptor (
       );\r
   }\r
 \r
+  //\r
+  // Code should never reach here.\r
+  //\r
+  ASSERT (FALSE);\r
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
@@ -784,6 +828,10 @@ GetAllocationDescriptorLsn (
     return EFI_SUCCESS;\r
   }\r
 \r
+  //\r
+  // Code should never reach here.\r
+  //\r
+  ASSERT (FALSE);\r
   return EFI_UNSUPPORTED;\r
 }\r
 \r
@@ -1090,7 +1138,10 @@ ReadFile (
     //\r
     // There are no extents for this FE/EFE. All data is inline.\r
     //\r
-    GetFileEntryData (FileEntryData, &Data, &Length);\r
+    Status = GetFileEntryData (FileEntryData, Volume->FileEntrySize, &Data, &Length);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
 \r
     if (ReadFileInfo->Flags == ReadFileGetFileSize) {\r
       ReadFileInfo->ReadLength = Length;\r
@@ -1134,7 +1185,11 @@ ReadFile (
     // This FE/EFE contains a run of Allocation Descriptors. Get data + size\r
     // for start reading them out.\r
     //\r
-    GetAdsInformation (FileEntryData, &Data, &Length);\r
+    Status = GetAdsInformation (FileEntryData, Volume->FileEntrySize, &Data, &Length);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
     AdOffset = 0;\r
 \r
     for (;;) {\r
@@ -1458,7 +1513,7 @@ InternalFindFile (
         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
@@ -1755,6 +1810,11 @@ FindFile (
   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
@@ -1946,22 +2006,38 @@ ReadDirectoryEntry (
   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
@@ -1974,10 +2050,22 @@ GetFileNameFromFid (
     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
@@ -1992,7 +2080,11 @@ GetFileNameFromFid (
     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
@@ -2000,6 +2092,12 @@ GetFileNameFromFid (
 /**\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
@@ -2121,6 +2219,10 @@ ResolveSymlink (
         return EFI_VOLUME_CORRUPTED;\r
       }\r
 \r
+      if ((UINTN)PathComp->ComponentIdentifier + PathCompLength > (UINTN)EndData) {\r
+        return EFI_VOLUME_CORRUPTED;\r
+      }\r
+\r
       Char = FileName;\r
       for (Index = 1; Index < PathCompLength; Index++) {\r
         if (CompressionId == 16) {\r
@@ -2128,6 +2230,9 @@ ResolveSymlink (
                           Index) << 8;\r
           Index++;\r
         } else {\r
+          if (Index > ARRAY_SIZE (FileName)) {\r
+            return EFI_UNSUPPORTED;\r
+          }\r
           *Char = 0;\r
         }\r
 \r
@@ -2138,7 +2243,11 @@ ResolveSymlink (
         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