Fix exFAT-on-GPT USB drives (and a UMS device-list use-after-free)#19
Open
crux161 wants to merge 5 commits into
Open
Fix exFAT-on-GPT USB drives (and a UMS device-list use-after-free)#19crux161 wants to merge 5 commits into
crux161 wants to merge 5 commits into
Conversation
exFAT volumes on GPT-partitioned USB drives already mount through libusbhsfs's upstream Microsoft Basic Data Partition path, but some drives leave uninitialized/garbage entries in the GPT partition array (type GUID 0xF4-filled, lba_start = 0xF4F4F4F4F4F4F4F4). The relaxed-gpt-vbr-probe patch probed any non-empty type GUID, so it issued reads at those absurd LBAs, triggering an "Invalid CSW" BOT mass-storage reset (~9s stall) that knocked flaky drives off the bus: the volume would register and then immediately disappear from the UI. Bounds-check entry_lba/lba_end against the logical unit's block_count before probing, so garbage entries are skipped while genuine non-Microsoft-GUID volumes are still detected. Also wire the patch into the Docker build and add a LIBUSBHSFS_DEBUG switch (links -lusbhsfsd) for capturing sd:/libusbhsfs.log when diagnosing mount issues. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
libusbhsfs invokes the populate callback from its background hotplug thread, which rewrote UmsController::devices while the render thread read it (settings USB table), freeing the device name/mount_name strings mid-copy: a data abort when opening or interacting with the settings pane while a USB drive was present. Guard the device list with a mutex: populate_devices, unmount_device and set_devices_changed_callback take the lock, get_devices() returns a copy under it, and finalize() snapshots before unmounting. Callbacks are invoked outside the lock to avoid re-entrancy. Harden the settings USB table accordingly: copy the device list for rendering, pass user-controlled strings through "%s" (the device name comes from USB descriptors and may contain %), and guard front() on a possibly-empty filesystem list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Reflow the two added comment blocks so each line is its own /* ... */, matching the surrounding code style, per review on the upstream PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reword the comment on the catch-all branch to state that it only handles entries with a non-empty, unrecognised type GUID (all-zero/empty entries are skipped via the g_emptyPartitionGuid check), per upstream review.
Owner
? The project carries no such patch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
exFAT-formatted, GPT-partitioned USB drives would not stay mounted in SwitchWave: a drive could be detected but its volume never appeared (or appeared and vanished) in the media list, and the Settings pane could crash while a USB drive was connected.
Two independent root causes, fixed here:
1. GPT VBR probe issued reads at garbage LBAs (the headline bug)
exFAT volumes on GPT already mount fine via libusbhsfs's upstream Microsoft Basic Data Partition path. The problem was the
relaxed-gpt-vbr-probepatch this project carries for libusbhsfs: it probed the VBR of any GPT entry with a non-empty type GUID. Some USB drives leave uninitialized/garbage entries in the GPT partition array (type GUID0xF4-filled,lba_start = 0xF4F4F4F4F4F4F4F4), so the probe issued reads at absurd LBAs, which triggered anInvalid CSWBOT mass-storage reset (~9 s stall) and knocked flaky drives off the bus — the volume registered and then immediately disappeared.Captured with a
LIBUSBHSFS_DEBUGbuild (sd:/libusbhsfs.log):Fix: bounds-check
entry_lba/lba_endagainst the logical unit'sblock_countbefore probing, so garbage entries are skipped while genuine non-Microsoft-GUID volumes are still detected. After the fix the same drive registers the FAT/exFAT volume and stays mounted, with no probe/reset/removal sequence. Playback from the exFAT key confirmed working.The patch wiring is added to the Docker build, plus a
LIBUSBHSFS_DEBUGswitch (links-lusbhsfsd) to makesd:/libusbhsfs.logavailable for future diagnosis.2. Use-after-free race in the UMS device list
libusbhsfs invokes the populate callback from its background hotplug thread, which rewrote
UmsController::deviceswhile the render thread read it (Settings USB table), freeing the devicename/mount_namestrings mid-copy — a data abort when opening/interacting with the Settings pane while a USB drive was present (same class as #18).Fix: guard the device list with a mutex (
populate_devices/unmount_device/set_devices_changed_callbacktake the lock,get_devices()returns a copy under it,finalize()snapshots before unmounting; callbacks run outside the lock). The Settings USB table is hardened to match: copy the list for rendering, route user-controlled strings through"%s"(device names come from USB descriptors and may contain%), and guardfront()on a possibly-empty filesystem list.Testing
./build-docker.sh(andLIBUSBHSFS_DEBUG=1 ./build-docker.sh).sd:/libusbhsfs.logshows a clean registration with no0xF4F4…probe /Invalid CSW/ drive removal.Notes
The bounds-check is fundamentally a libusbhsfs improvement; I'm also preparing an upstream PR to DarkMatterCore/libusbhsfs so the relaxed-but-bounded GPT probe can live there and this project can eventually drop the patch.
🤖 Generated with Claude Code