Repository navigation
nvx-rs: add a strict GPT reader for layered root disks - #673
Merged
Pedro Henrique Penna (ppenna) merged 3 commits intoOct 22, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
Static review found no blocking issues in the bounded parser or supplied test coverage; automated checks were not rerun.
No open issues 🎉
What changed in this PR
Adds a feature-free GPT reader shared by host and guest code, laying the groundwork for layered-root disk support in #621.
Changes:
- Validates primary GPT metadata, partition identities, and extents with bounded reads.
- Adds optional expectations and bounded, opaque p1 configuration reads.
- Adds crafted-disk tests and public API documentation.
| File | Description |
|---|---|
| nvx-rs/src/lib.rs | Exports and documents the GPT module. |
| nvx-rs/src/gpt/tests.rs | Tests validation, boundaries, sources, and p1 reads. |
| nvx-rs/src/gpt/source.rs | Provides memory and file read adapters. |
| nvx-rs/src/gpt/mod.rs | Implements parsing, validation, and p1 reads. |
| nvx-rs/src/gpt/guid.rs | Adds GPT GUID parsing and formatting. |
| nvx-rs/src/gpt/error.rs | Defines validation errors and diagnostics. |
| nvx-rs/src/gpt/crc.rs | Implements and tests CRC-32. |
| nvx-rs/README.md | Documents the module and feature-free availability. |
Review effort: Balanced
Add nvx::gpt, a reader of the GPT disks that hold a layered root: p1, whose bytes configure an adapter, and the read-only layers of the root in the partitions after it. Disk::read checks the protective MBR, the primary header, and the primary partition entry array as UEFI specifies them and as Linux's own GPT reader requires them, so that a disk that Linux would not read as this table fails early and clearly. It never reads the backup, allocates the entry array only once the header has bounded it, and checks its arithmetic in the disk's logical blocks. Expected adds the disk GUID and the partitions' unique GUIDs and sizes that a caller knows, and Disk::read_p1 returns p1's opaque bytes, up to the caller's bound and without trailing NUL bytes and whitespace. The module depends on nothing outside the standard library, so the guest's device validation and the host's checks of the images that it stages can share it. Part of #621. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1b4b569c-a481-43aa-bfd8-c14a9762c371
The crate meets UUIDs in several places: the GUIDs of a GPT disk and its partitions, the UUIDs of layers' filesystems, and the identities that a boot parameter names, which a guest compares with what a disk holds. Read the GPT reader's GUIDs as nvx::uuid::Uuid, the type that the boot tokens of a layered root already use, in place of its own Guid, so that these compare without a conversion through text. GPT, like other EFI GUIDs, stores the first three groups of a GUID little-endian, which Uuid::from_bytes_le and Uuid::to_bytes_le convert. Part of #621. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1b4b569c-a481-43aa-bfd8-c14a9762c371
Say in the CRC module's header that a CRC-32 is 32 bits, so that the CRC, its polynomial, and each entry of its table are u32s, and that the table holds the CRC of each of the 256 values of a byte. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1b4b569c-a481-43aa-bfd8-c14a9762c371
Enrique Saurez (esaurez)
force-pushed
the
esaurez/a3-gpt-validation-20261020
branch
from
October 22, 2026 04:31
2a43977 to
7265b64
Compare
Enrique Saurez (esaurez)
requested a review
from Pedro Henrique Penna (ppenna)
October 22, 2026 04:56
Pedro Henrique Penna (ppenna)
approved these changes
Oct 22, 2026
Pedro Henrique Penna (ppenna)
deleted the
esaurez/a3-gpt-validation-20261020
branch
October 22, 2026 15:25
This was referenced Oct 22, 2026
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.
Adds
nvx::gpt, a feature-free reader of the GPT disks that hold a layered root: p1, whose bytes configure an adapter, and the read-only layers of the root in the partitions after it. Its GUIDs arenvx::uuid::Uuids, the crate's one UUID type. This is the first part of GPT support in the guest library. The guest's device validation, which asks the kernel to reread the partition table and confirms that the kernel's partitions are exactly the ones read here, follows in a stacked pull request; mounting the layers comes after that.What changed
Disk::readreads the protective MBR, the primary GPT header, and the primary partition entry array through aReadAtsource that the caller gives (bytes in memory, a file, or, in the guest, a block device), with the logical block size and disk size that the caller states. It checks them strictly, as UEFI 2.10 specifies them and as Linux's own GPT reader requires them, so that a disk that Linux would not read as this table fails early and clearly:0xEErecord, starting at LBA 1, with the other three records zero, so a classic or hybrid MBR fails.MyLBA, and the layout2 <= entry LBA,entry LBA + entry blocks <= first usable <= last usable < alternate LBA <= last LBA.Expectedadds what a caller knows: the disk GUID, such as the one that a boot parameter names, and the count, unique GUIDs, and sizes of the partitions. Each expectation is optional and is checked after the format's own checks.Disk::read_p1returns p1's bytes, opaque and not necessarily UTF-8, without trailing NUL bytes and ASCII whitespace. A p1 larger than the caller's bound fails before any of it is read, and p1 is never probed as a filesystem.GptErrornames the check that failed; apart from failed reads, the checks run in the order of its variants.nvx::uuid::Uuids, so that a boot parameter's disk GUID, a disk's GUIDs, and a filesystem's UUID compare as one type, without a conversion through text.Uuid::from_bytes_leandto_bytes_leconvert the layout in which GPT, like other EFI GUIDs, stores the first three groups little-endian.Part of #621. Refs #622 and #535.
Validation
At this head, rebased onto
devat e714acb, on Windows 11 (MSVC, Rust 1.95.0) and on WSL Ubuntu as a non-root user (Rust 1.95.0), innvx-rswithNVX_BUNDLE=skip:cargo fmt --all --checkcargo clippy --locked --all-targets --all-features -- -D warningscargo clippy --locked --lib --no-default-features -- -D warningscargo test --locked --all-features, thencargo test --locked. The 30 new GPT tests write crafted disks of 512- and 4096-byte blocks field by field: every header and entry-array field, CRC failures, the protective MBR (classic, hybrid, and misplaced records), overflowing LBAs and sizes, overlaps, holes, 255 and 256 partitions, a corrupt primary table beside an intact backup, a source that records every read, mismatched expected identities and sizes, and p1 in one sector, with bytes that are not UTF-8, with NUL and whitespace padding, and over its bound.cargo doc --locked --no-deps --all-featureswithRUSTDOCFLAGS=-D warningscargo +1.89 check --locked --all-targets --all-features, the minimum supported Rust versiontests/runtime-adapterin its protocol-only and host-only configurations: rustfmt, Clippy, build, tests, and the 1.89 checkaci_edge_sandboxes, as its CI checks it, withACI_EDGE_SANDBOXES_AGENT_BUNDLE=skip: rustfmt, Clippy, tests,nvx.py test-agent-bundling, rustdoc, and its minimum supported Rust versionOn WSL Ubuntu only:
cargo check --locked --all-targets --all-features --target aarch64-apple-darwin, innvx-rsand inaci_edge_sandboxespython3 scripts/nvx.py check-guest-binaries,build-guest-binaries --output DIR, andtest-guest-binaries --binaries DIR. The nine guest binaries are byte-identical to those built fromdevat e714acb.tests/runtime-adapterin its musl guest-only configurationAnd
python scripts/nvx.py verifyandpython scripts/check_markdown_links.pyon Windows.This pull request changes no guest image, binary, or script, so I ran no microVM scenario for it; the stacked device validation pull request adds a GPT scenario and runs it on real VMs. CI runs the hypervisor matrix.