diff options
author | Oliver Smith-Denny <osde@microsoft.com> | 2025-01-10 14:42:17 -0800 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2025-01-21 18:40:11 +0000 |
commit | 58766a472932c485d41163b1746fb1d9e7984f07 (patch) | |
tree | 64a0872b9a62a95b0682a530f702f1b381a0044b /FatPkg/EnhancedFatDxe/Init.c | |
parent | 35232f165cba2314cb4af2e0a5aa2fbb23695a0a (diff) | |
download | edk2-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.c | 62 |
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;
}
|