summaryrefslogtreecommitdiffstats
path: root/FatPkg/EnhancedFatDxe/Init.c
diff options
context:
space:
mode:
authorOliver Smith-Denny <osde@microsoft.com>2025-01-10 14:42:17 -0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2025-01-21 18:40:11 +0000
commit58766a472932c485d41163b1746fb1d9e7984f07 (patch)
tree64a0872b9a62a95b0682a530f702f1b381a0044b /FatPkg/EnhancedFatDxe/Init.c
parent35232f165cba2314cb4af2e0a5aa2fbb23695a0a (diff)
downloadedk2-58766a472932c485d41163b1746fb1d9e7984f07.tar.gz
FatPkg: Validate Reserved FAT Entries on Volume Open
There are two reserved FAT entries in the FAT filesystem that are expected to have valid contents in them. Today the FAT drivers do not validate these entries when reading from a device for the first time. This can cause infinite loops in the FAT driver when trying to read corrupted disks as reported in https://github.com/tianocore/edk2/issues/9679. This PR follows the recommended update requested in that bug to check the two reserved FAT entries and validate their contents against the spec defined values in both FatPei and EnhancedFatDxe when opening a device for the first time. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
Diffstat (limited to 'FatPkg/EnhancedFatDxe/Init.c')
-rw-r--r--FatPkg/EnhancedFatDxe/Init.c62
1 files changed, 53 insertions, 9 deletions
diff --git a/FatPkg/EnhancedFatDxe/Init.c b/FatPkg/EnhancedFatDxe/Init.c
index 9c51ed5b7b..f020cf703d 100644
--- a/FatPkg/EnhancedFatDxe/Init.c
+++ b/FatPkg/EnhancedFatDxe/Init.c
@@ -96,14 +96,6 @@ FatAllocateVolume (
}
//
- // Initialize cache
- //
- Status = FatInitializeDiskCache (Volume);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
// Install our protocol interfaces on the device's handle
//
Status = gBS->InstallMultipleProtocolInterfaces (
@@ -237,6 +229,7 @@ FatOpenDevice (
UINTN SectorsPerFat;
UINT8 SectorsPerClusterAlignment;
UINT8 BlockAlignment;
+ UINTN ReservedFatEntry;
//
// Read the FAT_BOOT_SECTOR BPB info
@@ -423,7 +416,58 @@ FatOpenDevice (
// We are now defining FAT Type
//
Volume->FatType = FatType;
- ASSERT (FatType != FatUndefined);
+
+ //
+ // Initialize cache before we use the helper functions that hit the cache
+ //
+ Status = FatInitializeDiskCache (Volume);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check the reserved FAT entries to ensure they contain valid values
+ //
+ ReservedFatEntry = FatGetFatEntry (Volume, 0);
+ if (Volume->FatEntryBuffer == MAX_UINT32) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ // Reserved FAT entry 0 should contain the BPB_MEDIA byte value in the low 8 bits with all other bits set to 1
+ switch (FatType) {
+ case Fat12:
+ if ((ReservedFatEntry & FAT_CLUSTER_MASK_FAT12) != ((UINTN)FatBs.FatBsb.Media | 0xF00)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ break;
+
+ case Fat16:
+ if ((ReservedFatEntry & FAT_CLUSTER_MASK_FAT16) != ((UINTN)FatBs.FatBsb.Media | 0xFF00)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ break;
+
+ case Fat32:
+ // the upper 4 bits of a FAT32 entry are reserved, so are unchecked here
+ if ((ReservedFatEntry & FAT_CLUSTER_MASK_FAT32) != ((UINTN)FatBs.FatBsb.Media | 0x0FFFFF00)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ break;
+
+ default:
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ // Reserved FAT entry 1 should contain the end of chain mark. On FAT16 and FAT32, the high 2 bits may be used as
+ // dirty and hardware error bits, so are ignored in this check, but FatGetFatEntry already ignores them to unify the
+ // logic across FAT types
+ ReservedFatEntry = FatGetFatEntry (Volume, 1);
+ if ((Volume->FatEntryBuffer == MAX_UINT32) || !FAT_END_OF_FAT_CHAIN (ReservedFatEntry)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
return EFI_SUCCESS;
}