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

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