Skip to content

mount: probe VBR for GPT entries with unrecognized type GUIDs#32

Closed
crux161 wants to merge 1 commit into
DarkMatterCore:mainfrom
crux161:feature/gpt-unrecognized-vbr-probe
Closed

mount: probe VBR for GPT entries with unrecognized type GUIDs#32
crux161 wants to merge 1 commit into
DarkMatterCore:mainfrom
crux161:feature/gpt-unrecognized-vbr-probe

Conversation

@crux161

@crux161 crux161 commented May 29, 2026

Copy link
Copy Markdown

Summary

usbHsFsMountParseGuidPartitionTableEntry() currently inspects only Microsoft Basic Data and Linux Filesystem Data GPT entries. Some tools place otherwise standard exFAT/FAT/NTFS volumes behind non-standard partition type GUIDs, so those volumes are silently skipped and never mounted.

This adds a fall-through branch that probes the volume boot record for any entry whose type GUID is non-empty and wasn't handled by the dedicated branches — with an LBA bounds check first, which turned out to be essential.

Why the bounds check matters

Some USB drives leave uninitialized/garbage entries in the GPT partition array (observed in the wild: a type GUID that is 0xF4-filled, with lba_start == 0xF4F4F4F4F4F4F4F4). Probing such an entry without validation issues a read at an out-of-range LBA, which on flaky BOT drives produces an Invalid CSW, forces a mass-storage reset, and can knock the drive off the bus entirely — after a real volume on the same drive had already been registered.

So before probing, the entry's range is validated against lun_ctx->block_count:

if (memcmp(gpt_entry->type_guid, g_emptyPartitionGuid, sizeof(g_emptyPartitionGuid)) &&
    entry_lba && entry_lba < lun_ctx->block_count &&
    gpt_entry->lba_end >= entry_lba && gpt_entry->lba_end < lun_ctx->block_count)

Genuine non-Microsoft-GUID volumes are still detected; garbage entries are skipped without touching the device.

Testing

Built BUILD_TYPE=gpl for Switch (devkitA64) and exercised with the debug build (-lusbhsfsd, sd:/libusbhsfs.log) on real hardware (firmware 21.1.0 / Atmosphère 1.11.1):

  • Before: a GPT/exFAT drive registered its FAT volume, then the unbounded probe hit the 0xF4F4… entry → Invalid CSW → BOT reset → drive removed.
  • After: the same drive registers the volume and stays mounted; the garbage entry is skipped with no probe/reset/removal.

Discovered while adding exFAT-on-GPT support to SwitchWave (averne/SwitchWave#19), which had been carrying this as a local patch; upstreaming so it can be dropped there.

🤖 Generated with Claude Code

Comment thread source/usbhsfs_mount.c Outdated
Comment thread source/usbhsfs_mount.c Outdated
Comment thread source/usbhsfs_mount.c
Comment thread source/usbhsfs_mount.c Outdated
@DarkMatterCore DarkMatterCore added enhancement New feature or request good first issue Good for newcomers labels May 29, 2026
Only Microsoft Basic Data and Linux Filesystem Data GPT partition
entries are currently inspected, so standard filesystems placed behind
other type GUIDs are skipped. For example, the Windows Recovery
Environment partition created by Windows Setup uses type GUID
DE94BBA4-06D1-4D40-A16A-BFD50179D6AC yet holds an NTFS volume.

Probe the VBR (and, on GPL builds, the EXT superblock) for any entry
whose type GUID is non-empty and was not handled by the dedicated
branches.

A GPT entry's LBA span is also validated against the logical unit's
block_count at the top of the function, before any branch issues a
read. This guards every branch against uninitialized/garbage partition
array entries (e.g. a type GUID 0xF4-filled with lba_start ==
0xF4F4F4F4F4F4F4F4) whose reads would target out-of-range LBAs and can
stall flaky USB drives, force a BOT mass-storage reset and drop them
off the bus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@crux161 crux161 force-pushed the feature/gpt-unrecognized-vbr-probe branch from 2a55b2f to d1d1a02 Compare May 29, 2026 23:27
@crux161

crux161 commented May 29, 2026

Copy link
Copy Markdown
Author

Thanks for the review! Addressed all four points in the latest push:

  1. Bounds check moved to the top — the LBA-span validation now runs right after the variable declarations, before the first memcmp, and returns early (with a debug USBHSFS_LOG_MSG) when it fails. As a side benefit it now guards the Microsoft Basic Data and Linux Filesystem Data branches as well, not just the new one.
  2. Comment moved up with it.
  3. EXT probe added to the new branch under #ifdef GPL_BUILD, following the same logic as the other conditions.
  4. Example formatter named in the comment: the Windows Recovery Environment partition created by Windows Setup uses type GUID DE94BBA4-06D1-4D40-A16A-BFD50179D6AC yet holds an NTFS volume — a standard filesystem behind a non–Basic-Data / non-Linux GUID.

One small note on the bounds check: I deliberately left out an explicit lba_start != 0 term so that empty entries (all-zero GUID, 0/0 LBAs) still fall through to the GUID checks rather than being logged as discarded — otherwise every unused slot in a 128-entry array would emit a "discarding" line. Out-of-range garbage entries are still caught and logged.

Compiles cleanly for BUILD_TYPE=gpl (release + debug). The previous revision was verified on real hardware (a GPT/exFAT drive that the unbounded probe was knocking off the bus); this revision is behaviourally equivalent for that case — the garbage entry is still discarded by the bounds check and the exFAT volume still mounts via the Microsoft Basic Data path.

@DarkMatterCore

Copy link
Copy Markdown
Owner

@crux161

As a side note, two additional comments:

  • Please submit PRs to the dev branch whenever possible (that's actually on me, I haven't defined any PR policy document, sorry about that).
  • While I'm not 100% against the use of AI in software development, I prefer to limit its usage to situations like this one, where small yet somewhat meaningful bugs that were previously overlooked are fixed thanks to it. However, I personally blocked the Claude user on GitHub and updated the configuration of all of my repositories to opt out of AI training, which means that accepting this PR will inevitably make a quite unpleasant banner appear at the top of the repository. So please, resubmit this PR solely on your own and I will accept it.

crux161 added a commit to crux161/SwitchWave that referenced this pull request May 29, 2026
Match the revised DarkMatterCore/libusbhsfs#32 after maintainer review:
move the LBA bounds check to the top of the entry parser (guarding every
branch), probe the EXT superblock as well as the VBR for unrecognized
type GUIDs, and reference the Windows Recovery Environment partition as
a concrete example of a standard filesystem behind a non-standard GUID.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread source/usbhsfs_mount.c
Comment on lines +718 to +722
/* Discard entries whose LBA span falls outside this logical unit before any branch below
* issues a read. This filters out uninitialized/garbage partition array entries (e.g. a
* type GUID 0xF4-filled with lba_start == 0xF4F4F4F4F4F4F4F4) whose reads would target
* absurd LBAs, which can stall flaky USB drives, force a BOT reset and knock them off the bus. */
if (entry_lba >= lun_ctx->block_count || gpt_entry->lba_end >= lun_ctx->block_count || gpt_entry->lba_end < entry_lba)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make this comment block follow the same format as other multi-line comment blocks in this codebase by making each line sart with /* and end with */.

Comment thread source/usbhsfs_mount.c
Comment on lines +756 to +760
/* Some tools place standard exFAT/FAT/NTFS (or even EXT) volumes behind GPT type
* GUIDs other than the Microsoft Basic Data / Linux Filesystem Data ones handled
* above. For instance, the Windows Recovery Environment partition created by Windows
* Setup uses type GUID DE94BBA4-06D1-4D40-A16A-BFD50179D6AC, yet holds an NTFS volume.
* Probe the VBR (and, on GPL builds, the EXT superblock) before skipping the entry. */

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make this comment block follow the same format as other multi-line comment blocks in this codebase by making each line sart with /* and end with */.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought, the comment itself is misleading, since it doesn't really reference the fact that we're intentionally looking for an empty GUID here.

Comment thread source/usbhsfs_mount.c
Comment on lines +756 to +760
/* Some tools place standard exFAT/FAT/NTFS (or even EXT) volumes behind GPT type
* GUIDs other than the Microsoft Basic Data / Linux Filesystem Data ones handled
* above. For instance, the Windows Recovery Environment partition created by Windows
* Setup uses type GUID DE94BBA4-06D1-4D40-A16A-BFD50179D6AC, yet holds an NTFS volume.
* Probe the VBR (and, on GPL builds, the EXT superblock) before skipping the entry. */

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought, the comment itself is misleading, since it doesn't really reference the fact that we're intentionally looking for an empty GUID here.

@DarkMatterCore

Copy link
Copy Markdown
Owner

Superseded by #33. Closing this PR.

@crux161 crux161 deleted the feature/gpt-unrecognized-vbr-probe branch May 29, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants