macOS hardware audit: close the four checks, fix R-069 and R-070 - #82
Merged
Merged
Conversation
R6, R11, R19 and the read-only escalation fallback have survived two sessions because each needs removable media and a human at the keyboard. The 2026-09-08 attempt got no further: the USB floppy drive dropped off the bus mid-session, so an absent device answered ENXIO and nothing was verified. Collects what the next session needs in one place: that R-068 is the enabler (before it the documented R19 command could not work unprivileged), the exact commands and the verbatim log lines each check must produce, the hardware traps that cost the last attempt (a disappearing device reads as ENXIO, not EIO; an 800K Mac floppy is GCR and unreadable in a PC USB drive whatever size the drive reports), and the eight TEMP-DIAG sites to delete once R6 passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R-068 moved the raw-device check above the File::open that had preceded it, but only the one at the end of open_peeled_read_with_entry. The encrypted-DMG probe sits earlier in the same function, inside the default-on `crypto` feature, and opens the source unconditionally — so an unprivileged `rb-cli inspect /dev/rdiskN` still returned a bare EACCES before open_source_for_reading could run, with no dialog and no log output. The check now sits immediately after is_container_path, above every content probe: a raw device is never a container, an encrypted DMG or an NDIF fork carrier. try_decode_dart escaped the same bug only by accident, reading a metadata length that is 0 for a character device. Found on hardware while running the R-053 floppy check; with this in, the macOS device path reaches DA claim, elevation and the R6 write-protect warning on a physically locked disk for the first time from the CLI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Closes the four macOS hardware checks and removes the instrumentation
that was gated on one of them.
R-070: RestoreConfig::target_is_device comes straight from the --device
flag, so `rb-cli restore <backup> /dev/diskN` without it took run_restore's
image-file arm and opened the device with create(true).truncate(true).
O_TRUNC is ignored on a device node, so on writable media — or under sudo —
that arm writes to the raw device while skipping device_safety::preflight
and its system-disk guard, the DiskArbitration unmount, the disk claim, the
sector-aligned writer and open_target_for_writing's write-protect bail.
Found on hardware: only the card's lock switch stopped the write. A
device-shaped target without --device is now refused, naming the flag;
auto-enabling device mode was rejected because it turns a typo into a
whole-disk overwrite. Covered by device_target_needs_flag's tests.
TEMP-DIAG: describe_device_access and its seven call sites are gone. They
were kept only until the 2026-08-05 EACCES fix was confirmed on hardware,
which is what R6 did today.
Verification, all on hardware, 2026-09-08:
R6 write-protected media — read path escalates read-only and says
why with no second prompt; restore refuses with the write-path
message without touching the device (lock-switched SD card)
R11 a cancelled dialog — one prompt, no read-only retry, on the
O_RDWR path where the !is_authorization_cancelled guard runs
R19 raw-device reads — 1474560 bytes and an HFS superfloppy, not 0 B
Section 3 read-only fallback after a refused read-write escalation
Two log messages had lost their `\` line continuations, embedding 25 spaces
of source indentation into user-visible text; both are on the audited path.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A Rust `\`-newline escape had gone missing from four string literals, so
the source indentation became part of the message: 14 to 22 spaces sitting
mid-sentence in text the user reads.
src/cli/verbs/new_partitioned_hd.rs the HUNK_HEADER rejection
src/fs/ufs.rs the triple-indirect size ceiling
src/fs/ofs_write.rs the too-small-volume bail
src/fs/affs.rs the root-block search failure (three
runs in the one string)
Each now ends the line with a space then `\`, matching the convention in
src/os/macos.rs — the escape strips the newline and all leading whitespace
on the next line, so the separating space has to precede the backslash.
Same defect as the two repaired on the macOS elevation path in d7af8f4;
these were the rest of them. Verified by reading the strings back out of
the compiled binary, and with the vintage 1.73 proxy build since three of
the four are engine code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Closes the four open macOS hardware checks, fixes two High regressions found while running
them, and removes the instrumentation that was kept only until they were confirmed.
Verified on hardware; CI green on the branch head.
R-070 — a restore without
--devicewrote a device as if it were a fileRestoreConfig::target_is_devicecame straight from the--deviceflag, sorb-cli restore <backup> /dev/diskNwithout it tookrun_restore's image-file arm andopened the device with
create(true).truncate(true).O_TRUNCis ignored on a device node,so on writable media — or under
sudo— that arm wrote to the raw device while skippingevery guard that path exists to provide:
device_safety::preflightand its system-disk guardopen_target_for_writing's write-protect bailFound on hardware, where only the card's physical lock switch stopped the write.
A device-shaped target without
--deviceis now refused, naming the flag. Auto-enablingdevice mode was considered and rejected: it turns a typo into a whole-disk overwrite.
Covered by
device_target_needs_flag's tests.R-069 — the raw-device check ran after a content probe
R-068 moved the raw-device check above the
File::openthat had preceded it, but only theone at the end of
open_peeled_read_with_entry. The encrypted-DMG probe sits earlier in thesame function, inside the default-on
cryptofeature, and opened the sourceunconditionally — so an unprivileged
rb-cli inspect /dev/rdiskNstill returned a bareEACCESwith no dialog and no log output.The check now sits immediately after
is_container_path, above every content probe: araw device is never a container, an encrypted DMG, or an NDIF fork carrier.
try_decode_dartescaped the same bug only by accident, reading a metadata length that is 0 for a character
device.
Four error messages had lost their line continuations
A
\-newline escape had gone missing from four string literals, so the source indentationbecame part of the message — 14 to 22 spaces sitting mid-sentence in text the user reads:
src/cli/verbs/new_partitioned_hd.rssrc/fs/ufs.rssrc/fs/ofs_write.rssrc/fs/affs.rsEach now ends the line with a space then
\, matching the convention insrc/os/macos.rs—the escape strips the newline and all leading whitespace on the next line, so the
separating space has to precede the backslash. Same defect as the two repaired on the macOS
elevation path in
d7af8f41; these are the rest. Verified by reading the strings back outof the compiled binary, and with the vintage 1.73 proxy build, since three of the four are
engine code.
TEMP-DIAG removed
describe_device_accessand its seven call sites are gone. They were kept only until the2026-08-05 EACCES fix was confirmed on hardware, which R6 did.
Note on overlap with #81
src/os/mod.rsis the only file both branches touch, in different regions — this one removesdescribe_device_accessaround line 192, #81 adds a sync helper around line 544. They mergeclean.
Worth being explicit about one thing, since the symptoms look alike: the TEMP-DIAG here was
chasing a macOS restore failing with
Permission denied(os error 13) at the end of anotherwise successful run, and that is fixed. #81 fixes a different end-of-restore failure,
Inappropriate ioctl for device(os error 25) —ENOTTYfromF_FULLFSYNCon a rawdevice, after the data is already written. Different errno, different mechanism, both needed.
🤖 Generated with Claude Code