toyos-gpt: a Partition is only what parsing proved, and a bent GPT is refused (B1) - #547
Merged
Merged
Conversation
…is refused A USB stick whose CRC-valid GPT states an entry with first_lba > last_lba panicked the kernel on the next SYS_DEVICE_INVENTORY: `list` handed the entry back as a `Partition` with public fields, and `lba_count` underflowed (audit B1). - `Partition` has private fields and one constructor, `place`, which proves first_usable <= first <= last <= last_usable (< the device's block count) and computes `lba_count` once, as a `NonZeroU64`. `Located` is private too, so the overlap proof travels with it. - `list` and `locate_type` hand back each entry of the type as `Result<Partition, Unplaced>`: every consumer sees what the table states and has to handle the entry that is no partition. The kernel logs it and lists it nowhere; blockd refuses it as Unusable, as before. - The domain lint line forbids arithmetic side effects, indexing, unwrap, expect, panic and `as` in the crate; the CRC goes bit at a time, since a table lookup is an index. - tests/mutate.rs bends header and entry values of seeded layouts and reseals both CRCs; tests/oracle.rs reads every table against the `gpt` crate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reads Deleting `place`'s usable-range check left the oracle green: gpt checks no range, so an out-of-range partition agreed. UEFI 2.11 §5.3.3 is now applied to gpt's own decoding of the header, and that mutation reds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l lives `inspect dev.*` is SYS_DEVICE_INVENTORY, the call B1 panicked the kernel on. The crafted NVMe disk now states an entry at LBA 500..=400: the inventory lists it nowhere and the kernel's log names the refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…disk The `gpt` crate reads TOYOS-DATA's type back as unused, so rewriting the table through it handed DATA's slot to the backwards entry and dropped DATA. The entry is now written into the first free slot of both copies and both CRCs resealed; toyos-gpt reads the result as three partitions and one Unplaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu
marked this pull request as ready for review
September 27, 2026 15:16
Collaborator
Author
|
Review of #547 at 61ab220, round 1. CI at 61ab220: BLOCKER
NOTE
REMOVE
SEND BACK |
The CRC is table-driven again. The table is built by a split_first_mut walk and read with `get`, so the crate's lint line still forbids indexing and nothing in it is allowed locally. On this host's aarch64 and x86_64 the lookup compiles to the loop the indexed table did, with no `None` branch. A scan's slice is cleared before it is filled. Two parse.rs tests now hold that: a slice of stale entries listed over, and a primary whose extra entry and broken array CRC are retried against a good backup. Removing `out.fill(None)` turns both red. One image builder: parse.rs builds its fixed disks as a `table::Layout`, which gains `Table::mirror` and a failing read, and loses its own `Builder`. `Unplaced` and `Stated` are one public type, `Stated`; `place` hands it back when an entry's blocks are no partition. `TypeScan.listed` is gone, since every caller can derive it, and so are `MIN_LBA_BYTES` and `MAX_LBA_BYTES`, whose reason moves to `LbaSize`. The kernel logs an unplaced entry once, in `list`, not again in `collect`. The bootloader carries `Located` into `read_root`, so the overlap proof reaches the one read that depends on it. The oracle's usable-range arm is cut: it held toyos-gpt to its own predicate. inspectcase states its backwards entry on a USB stick (`Profile::GopUsbDisk`, `partclaim::craft_stick`), sealed by `volumes::rewrite_gpt`, and no longer crafts an NVMe disk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Review of #547 at f6b675c, round 2. CI at f6b675c: Round 1 BLOCKERs
BLOCKER
NOTE
REMOVE
SEND BACK |
src/metal.rs's one_partition and src/image.rs's only_partition each ran the
same locate_type scan into a three-way match on (matched, out[0]). Pull that
match into image::one_partition_of, returning Result<Partition,
OnePartitionError> where OnePartitionError carries either the Stated of an
unplaced entry or the matched count. only_partition turns that into its
String; metal::one_partition turns it into Refusal::Table or
Refusal::Partitions { what, matched }, keeping the count only metal.rs needed
back.
Also drops the PR body's unmeasured codegen sentence about aarch64 and
x86_64-unknown-none lookup compilation — no objdump or godbolt output backed
it.
Review round 2 of #547.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Sep 27, 2026
This was referenced Sep 27, 2026
Japabu
added a commit
that referenced
this pull request
Sep 27, 2026
BootDisk::table_at takes #547's scan: `locate_type` fills `[Option<Entry>; 2]`, an entry whose blocks are no partition is refused by name, and the one slot table is then `locate`d and read through `Partition`'s accessors. The SDK manifests take main's side: the publisher assigns their versions (#550). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu
added a commit
that referenced
this pull request
Sep 27, 2026
… under toyos-gpt's lints The merge took main's manifests (#550) but kept this branch's bumped toyos, toyos-abi and toyos-window versions in eight lockfiles; they now say what main says, and userland's keeps only the update binary's toyos-gpt dependency. #547 forbids indexing, `as` and unchecked arithmetic in toyos-gpt outside tests, and `Guid::parse` used all three. It now reads the dashes with `get`, the digits with `char::from`, and a byte with checked arithmetic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu
added a commit
that referenced
this pull request
Sep 27, 2026
…gpt) - toyos-abi, toyos and toyos-window take main's frozen versions and path dependencies; the lockfiles' SDK entries go back to them. - kernel/src/gpt.rs: main's `Option<Entry>` listing, with the branch's deletions of `collect`, `locate_log` and `BLANK` kept; `log_place` reads `unique_guid()`. - blockd: main's listing of an entry whose blocks are no partition, carrying the branch's `kind`. - inspect: main's crafted USB stick with its free, granted and backwards entries and their checks, beside the branch's blockd and fsd rows and its two partitions fsd holds; test-runner's granted partition is back in the config. Co-Authored-By: Claude Opus 5.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.
Stage F of the trust-boundary design. It fixes audit B1: a CRC-valid GPT whose entry has
first_lba > last_lbapanicked the kernel attoyos-gpt/src/lib.rs:171on the nextSYS_DEVICE_INVENTORY.listhanded the entry back as aPartitionwith public fields, andlba_countunderflowed.Every gate and control below ran at head
8d854908, which is merged with mainc9ed0125.Review round 2
src/metal.rs'sone_partitionandsrc/image.rs'sonly_partitioneach ran the samelocate_typescan into an identical three-way match on(scan.matched, out[0]). Pulled the match intoimage::one_partition_of, returningResult<toyos_gpt::Partition, OnePartitionError>whereOnePartitionErrorcarries either theStatedof an unplaced entry or the matched count.only_partitionturns that into itsString;metal::one_partitionturns it intoRefusal::TableorRefusal::Partitions { what, matched }— the countsrc/metal.rs's own test (an_image_admits_only_the_table_the_installed_rule_names) needs back. Each caller still builds its own[None; 2]and callslocate_typeitself; only the match moved.x86_64-unknown-nonelookup compilation. Noobjdump/godbolt output backed it.What changed, per decision
Partition's fields are private, and there is one constructor,place.placeprovesfirst_usable ≤ first ≤ last ≤ last_usable, wherelast_usableis below the device's block count.lba_countonce, as aNonZeroU64, and the accessors return it. Nothing outside the crate subtracts LBAs any more.Located. APartitionfromlistorlocate_typeis range-proven only. Onlylocatechecks overlap, and onlylocatemakes aLocated.Locatedintoread_root, so a scan result cannot reach the ROOT read.Volumeafterlocate.listandlocate_typefill&mut [Option<Entry>], whereEntry = Result<Partition, Stated>.Statedis the entry as the table states it.placehands it back when its blocks are no partition.list, and lists it nowhere: not in the inventory, not as a DATA candidate.Unusable.TypeScanismatched,disk_guidandused_entries. How many fit the slice is derived by each caller.toyos-gpt/src/lib.rs(arithmetic_side_effects,indexing_slicing,unwrap_used,expect_used,panic,as_conversions), with no localallow.const TABLE: [u32; 256]is built by asplit_first_mutwalk and read withTABLE.get(usize::from(low)).gpt.rs,inventory.rs;rootimage.rs;src/image.rs(with oneonly_partitionhelper),src/metal.rs;tests/common.toyos-gpt/tests/mutate.rs,tests/table/mod.rs). Seeded layouts get one to three header or entry values bent, and both CRC32s of both copies are resealed. 5,000 iterations run in the normal host run.count = last − first + 1; everyStatedhanded back really is not a partition; everylocateanswer and refusal is true of the table.parse.rsbuilds its fixed disks as atable::Layoutand flips bytes of the image, so the test crate has oneImage: Sectors.toyos-gpt/tests/oracle.rs) against thegptcrate, which is already resolved for the host. It is now a dev-dependency of toyos-gpt, andCargo.lockgains one line.inspect_reads_its_owners(Fast tier) runsinspect dev.*, which isSYS_DEVICE_INVENTORY.partclaim::craft_stick, newProfile::GopUsbDisk), because Storage: file servers for DATA, the log and the boot volume; the kernel's NVMe and FAT go #536 deletes the NVMe path. It carries the free partition, the granted one, and an entry at LBA 500..=400 written byvolumes::rewrite_gpt.Gates at
f6b675cb(exit codes)cargo run -- --ci host(48 steps: host workspace, every clippy shape including kernel x86/aarch64 and the bootloader)cargo test -p toyos-gpt(parse 43, mutate 1, oracle 3, unit 7)cargo clippy -p toyos-gpt --all-targets -- -D warningscargo test --test toyos-build -- inspect_reads_its_ownersGates at
8d854908(round 2, exit codes)cargo test --libcargo test -p toyos-gptcargo test --workspace --exclude toyos-buildcargo run -- --clippyCRC timing
The bench times
crc32over one 16 KiB array: the median of 5 interleaved rounds, each round the best of 5 × 20,000 calls, built withrustc -O --edition 2021. It ran on this host (aarch64), whose load average was 32.crc32.rsfrom6f0729ab(indexed table)61ab2201(bit at a time)f6b675cb(table read withget)Command, per version
vin a scratch directory holding that version'scrc32.rs(git show <rev>:toyos-gpt/src/crc32.rs):rustc -O --edition 2021 -o bench main.rs && ./benchNegative controls at
f6b675cbEach is a checked script: the patch is checked, the mutated tree is shown to build, then run, then reverted, and the tree is checked to be back where it was.
6f0729ab, except the test's premise:inspect.rs,inspectcase/system.toml, theGopUsbDiskprofile, andcraft_stickandrewrite_gptmadepub(super). The harness builds (exit 0).inspect_reads_its_ownersexits 1, the same failure wide and alone:inspect *.state exited Some(-1),attempt to subtract with overflow. That is B1, reached through a USB stick, and the kernel's syscall panic recovery killing the caller.out.fill(None): build 0,parseexit 101. Three tests go red:a_list_leaves_no_slot_it_did_not_fill,a_backup_retry_leaves_no_slot_of_the_primary, anda_type_scan_lists_every_entry_of_that_type.cargo clippy -p toyos-gpt --all-targets -- -D warningsexit 101:indexing may panicandusing a potentially dangerous silent as conversion.place's usable-range check: build 0, mutate exit 101. The oracle stays 0.check_no_overlapfromlocate: build 0, mutate exit 101. The oracle stays 0, because it reads throughlist, which makes no overlap claim.Independent oracles
gptcrate, above.Unsure
kernel/src/gpt.rs,tests/common/inspect.rs,userland/blockd/src/main.rs) and In QEMU, the loader writes boot variables on the running system's request and a failed pass falls to the entry behind its own or powers off; toyos-metal drives a boot through a machine running ToyOS alone #539 (bootloader/src/rootimage.rs). Both also use fields this branch makes private. The later lander adapts.🤖 Generated with Claude Code