Blame SOURCES/ovmf-MdeModulePkg-UdfDxe-Refine-boundary-checks-for-file-.patch

bdb79c
From 070a96e19dc08a87906035a1b0a67e8a3973a900 Mon Sep 17 00:00:00 2001
bdb79c
From: Laszlo Ersek <lersek@redhat.com>
bdb79c
Date: Fri, 22 Mar 2019 21:53:20 +0100
bdb79c
Subject: [PATCH 4/8] MdeModulePkg/UdfDxe: Refine boundary checks for file/path
bdb79c
 name string
bdb79c
MIME-Version: 1.0
bdb79c
Content-Type: text/plain; charset=UTF-8
bdb79c
Content-Transfer-Encoding: 8bit
bdb79c
bdb79c
Message-id: <20190322205323.17693-3-lersek@redhat.com>
bdb79c
Patchwork-id: 85132
bdb79c
O-Subject:  [RHEL-7.7 ovmf PATCH 2/5] MdeModulePkg/UdfDxe: Refine boundary checks
bdb79c
	for file/path name string
bdb79c
Bugzilla: 1691647
bdb79c
Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
bdb79c
Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
bdb79c
bdb79c
From: Hao Wu <hao.a.wu@intel.com>
bdb79c
bdb79c
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=828
bdb79c
bdb79c
The commit refines the boundary checks for file/path name string to
bdb79c
prevent possible buffer overrun.
bdb79c
bdb79c
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
bdb79c
Cc: Jiewen Yao <jiewen.yao@intel.com>
bdb79c
Contributed-under: TianoCore Contribution Agreement 1.1
bdb79c
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
bdb79c
Reviewed-by: Paulo Alcantara <palcantara@suse.de>
bdb79c
Acked-by: Star Zeng <star.zeng@intel.com>
bdb79c
(cherry picked from commit b9ae1705adfdd43668027a25a2b03c2e81960219)
bdb79c
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
bdb79c
---
bdb79c
 MdeModulePkg/Universal/Disk/UdfDxe/File.c          | 30 ++++++++--
bdb79c
 .../Universal/Disk/UdfDxe/FileSystemOperations.c   | 65 +++++++++++++++++++---
bdb79c
 MdeModulePkg/Universal/Disk/UdfDxe/Udf.h           | 30 +++++++++-
bdb79c
 3 files changed, 110 insertions(+), 15 deletions(-)
bdb79c
bdb79c
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/MdeModulePkg/Universal/Disk/UdfDxe/File.c
bdb79c
index 6f07bf2..bd723d0 100644
bdb79c
--- a/MdeModulePkg/Universal/Disk/UdfDxe/File.c
bdb79c
+++ b/MdeModulePkg/Universal/Disk/UdfDxe/File.c
bdb79c
@@ -2,6 +2,7 @@
bdb79c
   Handle operations in files and directories from UDF/ECMA-167 file systems.
bdb79c
 
bdb79c
   Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
bdb79c
+  Copyright (c) 2018, Intel Corporation. All rights reserved.
bdb79c
 
bdb79c
   This program and the accompanying materials are licensed and made available
bdb79c
   under the terms and conditions of the BSD License which accompanies this
bdb79c
@@ -248,7 +249,7 @@ UdfOpen (
bdb79c
     FileName = TempFileName + 1;
bdb79c
   }
bdb79c
 
bdb79c
-  StrCpyS (NewPrivFileData->FileName, UDF_PATH_LENGTH, FileName);
bdb79c
+  StrCpyS (NewPrivFileData->FileName, UDF_FILENAME_LENGTH, FileName);
bdb79c
 
bdb79c
   Status = GetFileSize (
bdb79c
     PrivFsData->BlockIo,
bdb79c
@@ -444,7 +445,7 @@ UdfRead (
bdb79c
       FreePool ((VOID *)NewFileEntryData);
bdb79c
       NewFileEntryData = FoundFile.FileEntry;
bdb79c
 
bdb79c
-      Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName);
bdb79c
+      Status = GetFileNameFromFid (NewFileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
bdb79c
       if (EFI_ERROR (Status)) {
bdb79c
         FreePool ((VOID *)FoundFile.FileIdentifierDesc);
bdb79c
         goto Error_Get_FileName;
bdb79c
@@ -456,7 +457,7 @@ UdfRead (
bdb79c
       FoundFile.FileIdentifierDesc  = NewFileIdentifierDesc;
bdb79c
       FoundFile.FileEntry           = NewFileEntryData;
bdb79c
 
bdb79c
-      Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName);
bdb79c
+      Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
bdb79c
       if (EFI_ERROR (Status)) {
bdb79c
         goto Error_Get_FileName;
bdb79c
       }
bdb79c
@@ -718,6 +719,12 @@ UdfSetPosition (
bdb79c
 /**
bdb79c
   Get information about a file.
bdb79c
 
bdb79c
+  @attention This is boundary function that may receive untrusted input.
bdb79c
+  @attention The input is from FileSystem.
bdb79c
+
bdb79c
+  The File Set Descriptor is external input, so this routine will do basic
bdb79c
+  validation for File Set Descriptor and report status.
bdb79c
+
bdb79c
   @param  This            Protocol instance pointer.
bdb79c
   @param  InformationType Type of information to return in Buffer.
bdb79c
   @param  BufferSize      On input size of buffer, on output amount of data in
bdb79c
@@ -794,6 +801,10 @@ UdfGetInfo (
bdb79c
         *String = *(UINT8 *)(OstaCompressed + Index) << 8;
bdb79c
         Index++;
bdb79c
       } else {
bdb79c
+        if (Index > ARRAY_SIZE (VolumeLabel)) {
bdb79c
+          return EFI_VOLUME_CORRUPTED;
bdb79c
+        }
bdb79c
+
bdb79c
         *String = 0;
bdb79c
       }
bdb79c
 
bdb79c
@@ -813,7 +824,11 @@ UdfGetInfo (
bdb79c
       String++;
bdb79c
     }
bdb79c
 
bdb79c
-    *String = L'\0';
bdb79c
+    Index = ((UINTN)String - (UINTN)VolumeLabel) / sizeof (CHAR16);
bdb79c
+    if (Index > ARRAY_SIZE (VolumeLabel) - 1) {
bdb79c
+      Index = ARRAY_SIZE (VolumeLabel) - 1;
bdb79c
+    }
bdb79c
+    VolumeLabel[Index] = L'\0';
bdb79c
 
bdb79c
     FileSystemInfoLength = StrSize (VolumeLabel) +
bdb79c
                            sizeof (EFI_FILE_SYSTEM_INFO);
bdb79c
@@ -823,8 +838,11 @@ UdfGetInfo (
bdb79c
     }
bdb79c
 
bdb79c
     FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
bdb79c
-    StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),
bdb79c
-             VolumeLabel);
bdb79c
+    StrCpyS (
bdb79c
+      FileSystemInfo->VolumeLabel,
bdb79c
+      (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16),
bdb79c
+      VolumeLabel
bdb79c
+      );
bdb79c
     Status = GetVolumeSize (
bdb79c
       PrivFsData->BlockIo,
bdb79c
       PrivFsData->DiskIo,
bdb79c
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c b/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
bdb79c
index ecc1723..424f41c 100644
bdb79c
--- a/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
bdb79c
+++ b/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
bdb79c
@@ -2,6 +2,7 @@
bdb79c
   Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
bdb79c
 
bdb79c
   Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
bdb79c
+  Copyright (c) 2018, Intel Corporation. All rights reserved.
bdb79c
 
bdb79c
   This program and the accompanying materials are licensed and made available
bdb79c
   under the terms and conditions of the BSD License which accompanies this
bdb79c
@@ -1412,7 +1413,7 @@ InternalFindFile (
bdb79c
         break;
bdb79c
       }
bdb79c
     } else {
bdb79c
-      Status = GetFileNameFromFid (FileIdentifierDesc, FoundFileName);
bdb79c
+      Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);
bdb79c
       if (EFI_ERROR (Status)) {
bdb79c
         break;
bdb79c
       }
bdb79c
@@ -1705,6 +1706,11 @@ FindFile (
bdb79c
   while (*FilePath != L'\0') {
bdb79c
     FileNamePointer = FileName;
bdb79c
     while (*FilePath != L'\0' && *FilePath != L'\\') {
bdb79c
+      if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=
bdb79c
+          (ARRAY_SIZE (FileName) - 1)) {
bdb79c
+        return EFI_NOT_FOUND;
bdb79c
+      }
bdb79c
+
bdb79c
       *FileNamePointer++ = *FilePath++;
bdb79c
     }
bdb79c
 
bdb79c
@@ -1882,22 +1888,38 @@ ReadDirectoryEntry (
bdb79c
   Get a filename (encoded in OSTA-compressed format) from a File Identifier
bdb79c
   Descriptor on an UDF volume.
bdb79c
 
bdb79c
+  @attention This is boundary function that may receive untrusted input.
bdb79c
+  @attention The input is from FileSystem.
bdb79c
+
bdb79c
+  The File Identifier Descriptor is external input, so this routine will do
bdb79c
+  basic validation for File Identifier Descriptor and report status.
bdb79c
+
bdb79c
   @param[in]   FileIdentifierDesc  File Identifier Descriptor pointer.
bdb79c
+  @param[in]   CharMax             The maximum number of FileName Unicode char,
bdb79c
+                                   including terminating null char.
bdb79c
   @param[out]  FileName            Decoded filename.
bdb79c
 
bdb79c
   @retval EFI_SUCCESS           Filename decoded and read.
bdb79c
   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
bdb79c
+  @retval EFI_BUFFER_TOO_SMALL  The string buffer FileName cannot hold the
bdb79c
+                                decoded filename.
bdb79c
 **/
bdb79c
 EFI_STATUS
bdb79c
 GetFileNameFromFid (
bdb79c
   IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,
bdb79c
+  IN   UINTN                           CharMax,
bdb79c
   OUT  CHAR16                          *FileName
bdb79c
   )
bdb79c
 {
bdb79c
-  UINT8 *OstaCompressed;
bdb79c
-  UINT8 CompressionId;
bdb79c
-  UINT8 Length;
bdb79c
-  UINTN Index;
bdb79c
+  UINT8  *OstaCompressed;
bdb79c
+  UINT8  CompressionId;
bdb79c
+  UINT8  Length;
bdb79c
+  UINTN  Index;
bdb79c
+  CHAR16 *FileNameBak;
bdb79c
+
bdb79c
+  if (CharMax == 0) {
bdb79c
+    return EFI_BUFFER_TOO_SMALL;
bdb79c
+  }
bdb79c
 
bdb79c
   OstaCompressed =
bdb79c
     (UINT8 *)(
bdb79c
@@ -1910,10 +1932,22 @@ GetFileNameFromFid (
bdb79c
     return EFI_VOLUME_CORRUPTED;
bdb79c
   }
bdb79c
 
bdb79c
+  FileNameBak = FileName;
bdb79c
+
bdb79c
   //
bdb79c
   // Decode filename.
bdb79c
   //
bdb79c
   Length = FileIdentifierDesc->LengthOfFileIdentifier;
bdb79c
+  if (CompressionId == 16) {
bdb79c
+    if (((UINTN)Length >> 1) > CharMax) {
bdb79c
+      return EFI_BUFFER_TOO_SMALL;
bdb79c
+    }
bdb79c
+  } else {
bdb79c
+    if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {
bdb79c
+      return EFI_BUFFER_TOO_SMALL;
bdb79c
+    }
bdb79c
+  }
bdb79c
+
bdb79c
   for (Index = 1; Index < Length; Index++) {
bdb79c
     if (CompressionId == 16) {
bdb79c
       *FileName = OstaCompressed[Index++] << 8;
bdb79c
@@ -1928,7 +1962,11 @@ GetFileNameFromFid (
bdb79c
     FileName++;
bdb79c
   }
bdb79c
 
bdb79c
-  *FileName = L'\0';
bdb79c
+  Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);
bdb79c
+  if (Index > CharMax - 1) {
bdb79c
+    Index = CharMax - 1;
bdb79c
+  }
bdb79c
+  FileNameBak[Index] = L'\0';
bdb79c
 
bdb79c
   return EFI_SUCCESS;
bdb79c
 }
bdb79c
@@ -1936,6 +1974,12 @@ GetFileNameFromFid (
bdb79c
 /**
bdb79c
   Resolve a symlink file on an UDF volume.
bdb79c
 
bdb79c
+  @attention This is boundary function that may receive untrusted input.
bdb79c
+  @attention The input is from FileSystem.
bdb79c
+
bdb79c
+  The Path Component is external input, so this routine will do basic
bdb79c
+  validation for Path Component and report status.
bdb79c
+
bdb79c
   @param[in]   BlockIo        BlockIo interface.
bdb79c
   @param[in]   DiskIo         DiskIo interface.
bdb79c
   @param[in]   Volume         UDF volume information structure.
bdb79c
@@ -2054,6 +2098,9 @@ ResolveSymlink (
bdb79c
                           Index) << 8;
bdb79c
           Index++;
bdb79c
         } else {
bdb79c
+          if (Index > ARRAY_SIZE (FileName)) {
bdb79c
+            return EFI_UNSUPPORTED;
bdb79c
+          }
bdb79c
           *Char = 0;
bdb79c
         }
bdb79c
 
bdb79c
@@ -2064,7 +2111,11 @@ ResolveSymlink (
bdb79c
         Char++;
bdb79c
       }
bdb79c
 
bdb79c
-      *Char = L'\0';
bdb79c
+      Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);
bdb79c
+      if (Index > ARRAY_SIZE (FileName) - 1) {
bdb79c
+        Index = ARRAY_SIZE (FileName) - 1;
bdb79c
+      }
bdb79c
+      FileName[Index] = L'\0';
bdb79c
       break;
bdb79c
     }
bdb79c
 
bdb79c
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
bdb79c
index d441539..9b82441 100644
bdb79c
--- a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
bdb79c
+++ b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
bdb79c
@@ -2,6 +2,7 @@
bdb79c
   UDF/ECMA-167 file system driver.
bdb79c
 
bdb79c
   Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
bdb79c
+  Copyright (c) 2018, Intel Corporation. All rights reserved.
bdb79c
 
bdb79c
   This program and the accompanying materials are licensed and made available
bdb79c
   under the terms and conditions of the BSD License which accompanies this
bdb79c
@@ -559,9 +560,16 @@ UdfSetPosition (
bdb79c
 /**
bdb79c
   Get information about a file.
bdb79c
 
bdb79c
+  @attention This is boundary function that may receive untrusted input.
bdb79c
+  @attention The input is from FileSystem.
bdb79c
+
bdb79c
+  The File Set Descriptor is external input, so this routine will do basic
bdb79c
+  validation for File Set Descriptor and report status.
bdb79c
+
bdb79c
   @param  This            Protocol instance pointer.
bdb79c
   @param  InformationType Type of information to return in Buffer.
bdb79c
-  @param  BufferSize      On input size of buffer, on output amount of data in buffer.
bdb79c
+  @param  BufferSize      On input size of buffer, on output amount of data in
bdb79c
+                          buffer.
bdb79c
   @param  Buffer          The buffer to return data.
bdb79c
 
bdb79c
   @retval EFI_SUCCESS          Data was returned.
bdb79c
@@ -571,7 +579,8 @@ UdfSetPosition (
bdb79c
   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
bdb79c
   @retval EFI_WRITE_PROTECTED  The device is write protected.
bdb79c
   @retval EFI_ACCESS_DENIED    The file was open for read only.
bdb79c
-  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
bdb79c
+  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
bdb79c
+                               BufferSize.
bdb79c
 
bdb79c
 **/
bdb79c
 EFI_STATUS
bdb79c
@@ -769,21 +778,38 @@ ReadDirectoryEntry (
bdb79c
   Get a filename (encoded in OSTA-compressed format) from a File Identifier
bdb79c
   Descriptor on an UDF volume.
bdb79c
 
bdb79c
+  @attention This is boundary function that may receive untrusted input.
bdb79c
+  @attention The input is from FileSystem.
bdb79c
+
bdb79c
+  The File Identifier Descriptor is external input, so this routine will do
bdb79c
+  basic validation for File Identifier Descriptor and report status.
bdb79c
+
bdb79c
   @param[in]   FileIdentifierDesc  File Identifier Descriptor pointer.
bdb79c
+  @param[in]   CharMax             The maximum number of FileName Unicode char,
bdb79c
+                                   including terminating null char.
bdb79c
   @param[out]  FileName            Decoded filename.
bdb79c
 
bdb79c
   @retval EFI_SUCCESS           Filename decoded and read.
bdb79c
   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
bdb79c
+  @retval EFI_BUFFER_TOO_SMALL  The string buffer FileName cannot hold the
bdb79c
+                                decoded filename.
bdb79c
 **/
bdb79c
 EFI_STATUS
bdb79c
 GetFileNameFromFid (
bdb79c
   IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,
bdb79c
+  IN   UINTN                           CharMax,
bdb79c
   OUT  CHAR16                          *FileName
bdb79c
   );
bdb79c
 
bdb79c
 /**
bdb79c
   Resolve a symlink file on an UDF volume.
bdb79c
 
bdb79c
+  @attention This is boundary function that may receive untrusted input.
bdb79c
+  @attention The input is from FileSystem.
bdb79c
+
bdb79c
+  The Path Component is external input, so this routine will do basic
bdb79c
+  validation for Path Component and report status.
bdb79c
+
bdb79c
   @param[in]   BlockIo        BlockIo interface.
bdb79c
   @param[in]   DiskIo         DiskIo interface.
bdb79c
   @param[in]   Volume         UDF volume information structure.
bdb79c
-- 
bdb79c
1.8.3.1
bdb79c