]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
MdeModulePkg/PartitionDxe: Skip the MBR that add for CD-ROM
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Udf.c
index c566bfc594d7ced79abd6703b6a86769b7fccb23..3bf89a187302ee49817e6a8e140f74fa11b91ec1 100644 (file)
@@ -1,19 +1,25 @@
 /** @file\r
   Scan for an UDF file system on a formatted media.\r
 \r
-  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+  Caution: This file requires additional review when modified.\r
+  This driver will have external input - CD/DVD media.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  FindUdfFileSystem() routine will consume the media properties and do basic\r
+  validation.\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
-  distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
+  Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
 #include "Partition.h"\r
 \r
+#define MAX_CORRECTION_BLOCKS_NUM 512u\r
+\r
 //\r
 // C5BD4D42-1A76-4996-8956-73CDA326CD0A\r
 //\r
@@ -27,6 +33,11 @@ typedef struct {
   EFI_DEVICE_PATH_PROTOCOL  End;\r
 } UDF_DEVICE_PATH;\r
 \r
+//\r
+// Vendor-Defined Device Path GUID for UDF file system\r
+//\r
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;\r
+\r
 //\r
 // Vendor-Defined Media Device Path for UDF file system\r
 //\r
@@ -43,77 +54,228 @@ UDF_DEVICE_PATH gUdfDevicePath = {
 /**\r
   Find the anchor volume descriptor pointer.\r
 \r
-  @param[in]  BlockIo             BlockIo interface.\r
-  @param[in]  DiskIo              DiskIo interface.\r
-  @param[out] AnchorPoint         Anchor volume descriptor pointer.\r
+  @param[in]  BlockIo               BlockIo interface.\r
+  @param[in]  DiskIo                DiskIo interface.\r
+  @param[out] AnchorPoint           Anchor volume descriptor pointer.\r
+  @param[out] LastRecordedBlock     Last recorded block.\r
 \r
-  @retval EFI_SUCCESS             Anchor volume descriptor pointer found.\r
-  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.\r
-  @retval other                   Anchor volume descriptor pointer not found.\r
+  @retval EFI_SUCCESS               Anchor volume descriptor pointer found.\r
+  @retval EFI_VOLUME_CORRUPTED      The file system structures are corrupted.\r
+  @retval other                     Anchor volume descriptor pointer not found.\r
 \r
 **/\r
 EFI_STATUS\r
 FindAnchorVolumeDescriptorPointer (\r
   IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,\r
   IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,\r
-  OUT  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint\r
+  OUT  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint,\r
+  OUT  EFI_LBA                               *LastRecordedBlock\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  UINT32      BlockSize;\r
-  EFI_LBA     EndLBA;\r
-  EFI_LBA     DescriptorLBAs[4];\r
-  UINTN       Index;\r
+  EFI_STATUS                            Status;\r
+  UINT32                                BlockSize;\r
+  EFI_LBA                               EndLBA;\r
+  UDF_DESCRIPTOR_TAG                    *DescriptorTag;\r
+  UINTN                                 AvdpsCount;\r
+  UINTN                                 Size;\r
+  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoints;\r
+  INTN                                  Index;\r
+  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPointPtr;\r
+  EFI_LBA                               LastAvdpBlockNum;\r
 \r
+  //\r
+  // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer\r
+  //\r
+  // An Anchor Volume Descriptor Pointer structure shall be recorded in at\r
+  // least 2 of the following 3 locations on the media: Logical Sector 256,\r
+  // N - 256 or N, where N is the last *addressable* sector of a volume.\r
+  //\r
+  // To figure out what logical sector N is, the SCSI commands READ CAPACITY and\r
+  // READ TRACK INFORMATION are used, however many drives or medias report their\r
+  // "last recorded block" wrongly. Although, READ CAPACITY returns the last\r
+  // readable data block but there might be unwritten blocks, which are located\r
+  // outside any track and therefore AVDP will not be found at block N.\r
+  //\r
+  // That said, we define a magic number of 512 blocks to be used as correction\r
+  // when attempting to find AVDP and define last block number.\r
+  //\r
   BlockSize = BlockIo->Media->BlockSize;\r
   EndLBA = BlockIo->Media->LastBlock;\r
-  DescriptorLBAs[0] = 256;\r
-  DescriptorLBAs[1] = EndLBA - 256;\r
-  DescriptorLBAs[2] = EndLBA;\r
-  DescriptorLBAs[3] = 512;\r
+  *LastRecordedBlock = EndLBA;\r
+  AvdpsCount = 0;\r
+\r
+  //\r
+  // Check if the block size of the underlying media can hold the data of an\r
+  // Anchor Volume Descriptor Pointer\r
+  //\r
+  if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: Media block size 0x%x unable to hold an AVDP.\n",\r
+      __FUNCTION__,\r
+      BlockSize\r
+      ));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Find AVDP at block 256\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 (256, BlockSize),\r
+    sizeof (*AnchorPoint),\r
+    AnchorPoint\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DescriptorTag = &AnchorPoint->DescriptorTag;\r
+\r
+  //\r
+  // Check if read block is a valid AVDP descriptor\r
+  //\r
+  if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
+    DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, 256));\r
+    AvdpsCount++;\r
+  }\r
+\r
+  //\r
+  // Find AVDP at block N - 256\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 ((UINT64)EndLBA - 256, BlockSize),\r
+    sizeof (*AnchorPoint),\r
+    AnchorPoint\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check if read block is a valid AVDP descriptor\r
+  //\r
+  if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer &&\r
+      ++AvdpsCount == 2) {\r
+    DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__,\r
+            EndLBA - 256));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Check if at least one AVDP was found in previous locations\r
+  //\r
+  if (AvdpsCount == 0) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  //\r
+  // Find AVDP at block N\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 ((UINT64)EndLBA, BlockSize),\r
+    sizeof (*AnchorPoint),\r
+    AnchorPoint\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check if read block is a valid AVDP descriptor\r
+  //\r
+  if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // No AVDP found at block N. Possibly drive/media returned bad last recorded\r
+  // block, or it is part of unwritten data blocks and outside any track.\r
+  //\r
+  // Search backwards for an AVDP from block N-1 through\r
+  // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block\r
+  // number for the new UDF partition child handle.\r
+  //\r
+  Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;\r
+\r
+  AnchorPoints = AllocateZeroPool (Size);\r
+  if (AnchorPoints == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),\r
+    Size,\r
+    AnchorPoints\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Out_Free;\r
+  }\r
+\r
+  Status = EFI_VOLUME_CORRUPTED;\r
+\r
+  //\r
+  // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM\r
+  //\r
+  for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {\r
+    AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);\r
+\r
+    DescriptorTag = &AnchorPointPtr->DescriptorTag;\r
 \r
-  for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {\r
-    Status = DiskIo->ReadDisk (\r
-      DiskIo,\r
-      BlockIo->Media->MediaId,\r
-      MultU64x32 (DescriptorLBAs[Index], BlockSize),\r
-      sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),\r
-      (VOID *)AnchorPoint\r
-      );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
     //\r
-    // Check if read LBA has a valid AVDP descriptor.\r
+    // Check if read block is a valid AVDP descriptor\r
     //\r
-    if (IS_AVDP (AnchorPoint)) {\r
-      return EFI_SUCCESS;\r
+    if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {\r
+      //\r
+      // Calculate last recorded block number\r
+      //\r
+      LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);\r
+      DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", __FUNCTION__,\r
+              LastAvdpBlockNum));\r
+      DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n",\r
+              __FUNCTION__, EndLBA, LastAvdpBlockNum));\r
+      //\r
+      // Save read AVDP from last block\r
+      //\r
+      CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));\r
+      //\r
+      // Set last recorded block number\r
+      //\r
+      *LastRecordedBlock = LastAvdpBlockNum;\r
+      Status = EFI_SUCCESS;\r
+      break;\r
     }\r
   }\r
-  //\r
-  // No AVDP found.\r
-  //\r
-  return EFI_VOLUME_CORRUPTED;\r
+\r
+Out_Free:\r
+  FreePool (AnchorPoints);\r
+  return Status;\r
 }\r
 \r
 /**\r
-  Check if block device supports a valid UDF file system as specified by OSTA\r
-  Universal Disk Format Specification 2.60.\r
+  Find UDF volume identifiers in a Volume Recognition Sequence.\r
 \r
-  @param[in]   BlockIo  BlockIo interface.\r
-  @param[in]   DiskIo   DiskIo interface.\r
+  @param[in]  BlockIo             BlockIo interface.\r
+  @param[in]  DiskIo              DiskIo interface.\r
 \r
-  @retval EFI_SUCCESS          UDF file system found.\r
-  @retval EFI_UNSUPPORTED      UDF file system not found.\r
-  @retval EFI_NO_MEDIA         The device has no media.\r
-  @retval EFI_DEVICE_ERROR     The device reported an error.\r
-  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
-  @retval EFI_OUT_OF_RESOURCES The scan was not successful due to lack of\r
-                               resources.\r
+  @retval EFI_SUCCESS             UDF volume identifiers were found.\r
+  @retval EFI_NOT_FOUND           UDF volume identifiers were not found.\r
+  @retval other                   Failed to perform disk I/O.\r
 \r
 **/\r
 EFI_STATUS\r
-SupportUdfFileSystem (\r
+FindUdfVolumeIdentifiers (\r
   IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
   IN EFI_DISK_IO_PROTOCOL   *DiskIo\r
   )\r
@@ -123,7 +285,6 @@ SupportUdfFileSystem (
   UINT64                                EndDiskOffset;\r
   CDROM_VOLUME_DESCRIPTOR               VolDescriptor;\r
   CDROM_VOLUME_DESCRIPTOR               TerminatingVolDescriptor;\r
-  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;\r
 \r
   ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));\r
 \r
@@ -162,7 +323,7 @@ SupportUdfFileSystem (
         (CompareMem ((VOID *)&VolDescriptor,\r
                      (VOID *)&TerminatingVolDescriptor,\r
                      sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {\r
-      return EFI_UNSUPPORTED;\r
+      return EFI_NOT_FOUND;\r
     }\r
   }\r
 \r
@@ -171,7 +332,7 @@ SupportUdfFileSystem (
   //\r
   Offset += UDF_LOGICAL_SECTOR_SIZE;\r
   if (Offset >= EndDiskOffset) {\r
-    return EFI_UNSUPPORTED;\r
+    return EFI_NOT_FOUND;\r
   }\r
 \r
   Status = DiskIo->ReadDisk (\r
@@ -191,7 +352,7 @@ SupportUdfFileSystem (
       (CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
                    (VOID *)UDF_NSR3_IDENTIFIER,\r
                    sizeof (VolDescriptor.Unknown.Id)) != 0)) {\r
-    return EFI_UNSUPPORTED;\r
+    return EFI_NOT_FOUND;\r
   }\r
 \r
   //\r
@@ -199,7 +360,7 @@ SupportUdfFileSystem (
   //\r
   Offset += UDF_LOGICAL_SECTOR_SIZE;\r
   if (Offset >= EndDiskOffset) {\r
-    return EFI_UNSUPPORTED;\r
+    return EFI_NOT_FOUND;\r
   }\r
 \r
   Status = DiskIo->ReadDisk (\r
@@ -216,15 +377,305 @@ SupportUdfFileSystem (
   if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,\r
                   (VOID *)UDF_TEA_IDENTIFIER,\r
                   sizeof (VolDescriptor.Unknown.Id)) != 0) {\r
-    return EFI_UNSUPPORTED;\r
+    return EFI_NOT_FOUND;\r
   }\r
 \r
-  Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if Logical Volume Descriptor is supported by current EDK2 UDF file\r
+  system implementation.\r
+\r
+  @param[in]  LogicalVolDesc  Logical Volume Descriptor pointer.\r
+\r
+  @retval TRUE                Logical Volume Descriptor is supported.\r
+  @retval FALSE               Logical Volume Descriptor is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+IsLogicalVolumeDescriptorSupported (\r
+  UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc\r
+  )\r
+{\r
+  //\r
+  // Check for a valid UDF revision range\r
+  //\r
+  switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {\r
+  case 0x0102:\r
+  case 0x0150:\r
+  case 0x0200:\r
+  case 0x0201:\r
+  case 0x0250:\r
+  case 0x0260:\r
+    break;\r
+  default:\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check for a single Partition Map\r
+  //\r
+  if (LogicalVolDesc->NumberOfPartitionMaps > 1) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // UDF 1.02 revision supports only Type 1 (Physical) partitions, but\r
+  // let's check it any way.\r
+  //\r
+  // PartitionMap[0] -> type\r
+  // PartitionMap[1] -> length (in bytes)\r
+  //\r
+  if (LogicalVolDesc->PartitionMaps[0] != 1 ||\r
+      LogicalVolDesc->PartitionMaps[1] != 6) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Find UDF logical volume location and whether it is supported by current EDK2\r
+  UDF file system implementation.\r
+\r
+  @param[in]  BlockIo               BlockIo interface.\r
+  @param[in]  DiskIo                DiskIo interface.\r
+  @param[in]  AnchorPoint           Anchor volume descriptor pointer.\r
+  @param[in]  LastRecordedBlock     Last recorded block in media.\r
+  @param[out] MainVdsStartBlock     Main VDS starting block number.\r
+  @param[out] MainVdsEndBlock       Main VDS ending block number.\r
+\r
+  @retval EFI_SUCCESS               UDF logical volume was found.\r
+  @retval EFI_VOLUME_CORRUPTED      UDF file system structures are corrupted.\r
+  @retval EFI_UNSUPPORTED           UDF logical volume is not supported.\r
+  @retval other                     Failed to perform disk I/O.\r
+\r
+**/\r
+EFI_STATUS\r
+FindLogicalVolumeLocation (\r
+  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,\r
+  IN   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint,\r
+  IN   EFI_LBA                               LastRecordedBlock,\r
+  OUT  UINT64                                *MainVdsStartBlock,\r
+  OUT  UINT64                                *MainVdsEndBlock\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINT32                         BlockSize;\r
+  UDF_EXTENT_AD                  *ExtentAd;\r
+  UINT64                         SeqBlocksNum;\r
+  UINT64                         SeqStartBlock;\r
+  UINT64                         GuardMainVdsStartBlock;\r
+  VOID                           *Buffer;\r
+  UINT64                         SeqEndBlock;\r
+  BOOLEAN                        StopSequence;\r
+  UINTN                          LvdsCount;\r
+  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;\r
+  UDF_DESCRIPTOR_TAG             *DescriptorTag;\r
+\r
+  BlockSize = BlockIo->Media->BlockSize;\r
+  ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;\r
+\r
+  //\r
+  // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent\r
+  //\r
+  // The Main Volume Descriptor Sequence Extent shall have a minimum length of\r
+  // 16 logical sectors.\r
+  //\r
+  // Also make sure it does not exceed maximum number of blocks in the disk.\r
+  //\r
+  SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);\r
+  if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  //\r
+  // Check for valid Volume Descriptor Sequence starting block number\r
+  //\r
+  SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;\r
+  if (SeqStartBlock > LastRecordedBlock ||\r
+      SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  GuardMainVdsStartBlock = SeqStartBlock;\r
+\r
+  //\r
+  // Allocate buffer for reading disk blocks\r
+  //\r
+  Buffer = AllocateZeroPool ((UINTN)BlockSize);\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SeqEndBlock = SeqStartBlock + SeqBlocksNum;\r
+  StopSequence = FALSE;\r
+  LvdsCount = 0;\r
+  Status = EFI_VOLUME_CORRUPTED;\r
+  //\r
+  // Start Main Volume Descriptor Sequence\r
+  //\r
+  for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {\r
+    //\r
+    // Read disk block\r
+    //\r
+    Status = BlockIo->ReadBlocks (\r
+      BlockIo,\r
+      BlockIo->Media->MediaId,\r
+      SeqStartBlock,\r
+      BlockSize,\r
+      Buffer\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Out_Free;\r
+    }\r
+\r
+    DescriptorTag = Buffer;\r
+\r
+    //\r
+    // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence\r
+    //\r
+    // - A Volume Descriptor Sequence shall contain one or more Primary Volume\r
+    //   Descriptors.\r
+    // - A Volume Descriptor Sequence shall contain zero or more Implementation\r
+    //   Use Volume Descriptors.\r
+    // - A Volume Descriptor Sequence shall contain zero or more Partition\r
+    //   Descriptors.\r
+    // - A Volume Descriptor Sequence shall contain zero or more Logical Volume\r
+    //   Descriptors.\r
+    // - A Volume Descriptor Sequence shall contain zero or more Unallocated\r
+    //   Space Descriptors.\r
+    //\r
+    switch (DescriptorTag->TagIdentifier) {\r
+    case UdfPrimaryVolumeDescriptor:\r
+    case UdfImplemenationUseVolumeDescriptor:\r
+    case UdfPartitionDescriptor:\r
+    case UdfUnallocatedSpaceDescriptor:\r
+      break;\r
+\r
+    case UdfLogicalVolumeDescriptor:\r
+      LogicalVolDesc = Buffer;\r
+\r
+      //\r
+      // Check for existence of a single LVD and whether it is supported by\r
+      // current EDK2 UDF file system implementation.\r
+      //\r
+      if (++LvdsCount > 1 ||\r
+          !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {\r
+        Status = EFI_UNSUPPORTED;\r
+        StopSequence = TRUE;\r
+      }\r
+\r
+      break;\r
+\r
+    case UdfTerminatingDescriptor:\r
+      //\r
+      // Stop the sequence when we find a Terminating Descriptor\r
+      // (aka Unallocated Sector), se we don't have to walk all the unallocated\r
+      // area unnecessarily.\r
+      //\r
+      StopSequence = TRUE;\r
+      break;\r
+\r
+    default:\r
+      //\r
+      // An invalid Volume Descriptor has been found in the sequece. Volume is\r
+      // corrupted.\r
+      //\r
+      Status = EFI_VOLUME_CORRUPTED;\r
+      goto Out_Free;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check if LVD was found\r
+  //\r
+  if (!EFI_ERROR (Status) && LvdsCount == 1) {\r
+    *MainVdsStartBlock = GuardMainVdsStartBlock;\r
+    //\r
+    // We do not need to read either LVD or PD descriptors to know the last\r
+    // valid block in the found UDF file system. It's already\r
+    // LastRecordedBlock.\r
+    //\r
+    *MainVdsEndBlock = LastRecordedBlock;\r
+\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Out_Free:\r
+  //\r
+  // Free block read buffer\r
+  //\r
+  FreePool (Buffer);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Find a supported UDF file system in block device.\r
+\r
+  @attention This is boundary function that may receive untrusted input.\r
+  @attention The input is from Partition.\r
+\r
+  The CD/DVD media is the external input, so this routine will do basic\r
+  validation for the media.\r
+\r
+  @param[in]  BlockIo             BlockIo interface.\r
+  @param[in]  DiskIo              DiskIo interface.\r
+  @param[out] StartingLBA         UDF file system starting LBA.\r
+  @param[out] EndingLBA           UDF file system starting LBA.\r
+\r
+  @retval EFI_SUCCESS             UDF file system was found.\r
+  @retval other                   UDF file system was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindUdfFileSystem (\r
+  IN EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  OUT EFI_LBA               *StartingLBA,\r
+  OUT EFI_LBA               *EndingLBA\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;\r
+  EFI_LBA                               LastRecordedBlock;\r
+\r
+  //\r
+  // Find UDF volume identifiers\r
+  //\r
+  Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_UNSUPPORTED;\r
+    return Status;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  //\r
+  // Find Anchor Volume Descriptor Pointer\r
+  //\r
+  Status = FindAnchorVolumeDescriptorPointer (\r
+    BlockIo,\r
+    DiskIo,\r
+    &AnchorPoint,\r
+    &LastRecordedBlock\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Find Logical Volume location\r
+  //\r
+  Status = FindLogicalVolumeLocation (\r
+    BlockIo,\r
+    DiskIo,\r
+    &AnchorPoint,\r
+    LastRecordedBlock,\r
+    (UINT64 *)StartingLBA,\r
+    (UINT64 *)EndingLBA\r
+    );\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -258,12 +709,13 @@ PartitionInstallUdfChildHandles (
   UINT32                       RemainderByMediaBlockSize;\r
   EFI_STATUS                   Status;\r
   EFI_BLOCK_IO_MEDIA           *Media;\r
-  EFI_DEVICE_PATH_PROTOCOL     *DevicePathNode;\r
-  EFI_GUID                     *VendorDefinedGuid;\r
-  EFI_GUID                     UdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;\r
   EFI_PARTITION_INFO_PROTOCOL  PartitionInfo;\r
+  EFI_LBA                      StartingLBA;\r
+  EFI_LBA                      EndingLBA;\r
+  BOOLEAN                      ChildCreated;\r
 \r
   Media = BlockIo->Media;\r
+  ChildCreated = FALSE;\r
 \r
   //\r
   // Check if UDF logical block size is multiple of underlying device block size\r
@@ -277,37 +729,30 @@ PartitionInstallUdfChildHandles (
     return EFI_NOT_FOUND;\r
   }\r
 \r
-  DevicePathNode = DevicePath;\r
-  while (!IsDevicePathEnd (DevicePathNode)) {\r
-    //\r
-    // Do not allow checking for UDF file systems in CDROM "El Torito"\r
-    // partitions, and skip duplicate installation of UDF file system child\r
-    // nodes.\r
-    //\r
-    if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) {\r
-      if (DevicePathSubType (DevicePathNode) == MEDIA_CDROM_DP) {\r
-        return EFI_NOT_FOUND;\r
-      }\r
-      if (DevicePathSubType (DevicePathNode) == MEDIA_VENDOR_DP) {\r
-        VendorDefinedGuid = (EFI_GUID *)((UINTN)DevicePathNode +\r
-                                         OFFSET_OF (VENDOR_DEVICE_PATH, Guid));\r
-        if (CompareGuid (VendorDefinedGuid, &UdfDevPathGuid)) {\r
-          return EFI_NOT_FOUND;\r
-        }\r
-      }\r
-    }\r
-    //\r
-    // Try next device path node\r
-    //\r
-    DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+  //\r
+  // Detect El Torito feature first.\r
+  // And always continue to search for UDF.\r
+  //\r
+  Status = PartitionInstallElToritoChildHandles (\r
+             This,\r
+             Handle,\r
+             DiskIo,\r
+             DiskIo2,\r
+             BlockIo,\r
+             BlockIo2,\r
+             DevicePath\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));\r
+    ChildCreated = TRUE;\r
   }\r
 \r
   //\r
-  // Check if block device supports an UDF file system\r
+  // Search for an UDF file system on block device\r
   //\r
-  Status = SupportUdfFileSystem (BlockIo, DiskIo);\r
+  Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_NOT_FOUND;\r
+    return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);\r
   }\r
 \r
   //\r
@@ -330,13 +775,14 @@ PartitionInstallUdfChildHandles (
     DevicePath,\r
     (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,\r
     &PartitionInfo,\r
-    0,\r
-    Media->LastBlock,\r
-    Media->BlockSize\r
+    StartingLBA,\r
+    EndingLBA,\r
+    Media->BlockSize,\r
+    NULL\r
     );\r
-  if (!EFI_ERROR (Status)) {\r
-    Status = EFI_NOT_FOUND;\r
+  if (EFI_ERROR (Status)) {\r
+    return (ChildCreated ? EFI_SUCCESS : Status);\r
   }\r
 \r
-  return Status;\r
+  return EFI_SUCCESS;\r
 }\r