Repository navigation
cli: check the command line that a sandbox launches (SL6.0f) - #1526
Merged
Pedro Henrique Penna (ppenna) merged 1 commit intoNov 12, 2026
Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
Pedro Henrique Penna (ppenna) merged 1 commit into
Conversation
Contributor
This pull request changes existing testsIt modifies or removes 2 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests. Test code
Relocated unchanged: 0; added: 1. Compared the merge base |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The command-line validation can mistake a user-supplied x for its sentinel, allowing -- to hide required device/bootstrap tokens from Linux and prevent guest boot.
1 open issue
What changed in this PR
Moves sandbox command-line validation to the line rendered by VmConfig, preparing for removal of the legacy launch code in SL6.3.
Changes:
- Checks the rendered sandbox line’s byte budget, reserved tokens, root compatibility, and visibility of appended tokens.
- Shares export-token accounting between sandbox launches and
nvx-rs run. - Adds boundary and refusal tests and updates command-line documentation.
| File | Description |
|---|---|
nvx-rs/tests/cli/lifecycle.rs |
Adds a start refusal case for --. |
nvx-rs/src/host/cli/sandbox/state.rs |
Removes the unused hostname accessor. |
nvx-rs/src/host/cli/sandbox/mod.rs |
Adds shared export-bootstrap token rendering. |
nvx-rs/src/host/cli/sandbox/lifecycle/start/tests.rs |
Tests exact byte limits and invalid command lines. |
nvx-rs/src/host/cli/sandbox/lifecycle/start.rs |
Validates the rendered VM command line instead of the legacy plan. |
nvx-rs/src/host/cli/run/tests.rs |
Updates budget tests and pins writable export tokens. |
nvx-rs/src/host/cli/run.rs |
Uses the shared export renderer and retained budget constant. |
doc/usage.md |
Clarifies --cmdline restrictions. |
doc/run.md |
Documents validation order and quote restrictions. |
Review effort: Balanced
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-0f-cli-command-line
branch
from
November 12, 2026 08:55
69ba1d6 to
de3c4bc
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-0f-cli-command-line
branch
from
November 12, 2026 09:36
de3c4bc to
93469a4
Compare
`sandbox start` and `sandbox run` refused a kernel command line through the old launch profile of `host::sandbox`: `check_command_line` built a `SandboxLaunch` of the configuration, with a `SandboxUpper` and `SandboxSettings`, bound its plan to the distro binding, and rendered the plan's kernel command line, which put the user's `--cmdline` first and left out the managed lifecycle's own tokens. `nvx-rs run` checked its shares against the kernel's budget with `host::sandbox`'s `SANDBOX_COMMAND_LINE_MAX_SIZE` and `export_command_line_fragment`. These were the CLI's last uses of the old launch. Both now check the command line that they launch, the one that the VM's `VmConfig` renders, with the CLI's own pieces: - `check_command_line` takes the sandbox's configuration and its `VmConfig`. It refuses the user's part as before: a NUL, and a token that the sandbox profile or `--mount` owns, `nvx_*` or `virtfs_*`, as Linux or the guest's init reads it, with the same messages. It then checks the launched line, with the bootstrap tokens of the shares and a NUL, against `host::config::COMMAND_LINE_BUDGET`, the same 1024 bytes as `SANDBOX_COMMAND_LINE_MAX_SIZE`, and reads the root's boot tokens from it with `RootLayout::parse`, with the old messages. - `export_tokens` renders the bootstrap tokens that OpenVMM appends for an export at `/run/nvx/hostfs/root`, as `export_command_line_fragment` rendered them, for both checks. The user's part now follows the root's tokens, which it can no longer hide, but it precedes the tokens that OpenVMM appends, the virtio-mmio devices of the root's disks among them. A `--` or an unclosed quote, as Linux reads them, would hide those, so the check refuses the line that Linux does not read to its end, where the old check refused one that hid the root's tokens, and its message names OpenVMM's tokens. That includes a `--` after a byte that only Linux takes for whitespace, such as the 0xa0 that ends `à`, which the control console's check of `VmConfig` does not see, since it splits at ASCII whitespace. The check appends a parameter that the user's part cannot name, since it holds no `nvx_*` token, and requires Linux to read it last. Closed double quotes stay refused as before: `sandbox run` refuses them with `VmConfig::check_command_line`, which it called already, and a start when it creates its VM. The user's part is checked as given, not trimmed, since the launched line holds it as given. `Config::hostname` loses its last caller and goes. Docs: `doc/usage.md` and `doc/run.md` say how `--cmdline` is checked. They still said that quoted values keep their whitespace and that a `--` or a quote hides the root's tokens. Tests: `starts_check_the_kernel_command_line_that_they_launch` fills the budget to the byte with and without shares, over scratch and in RAM, pins the tokens of a read-only export, and pins the refusals of a NUL, of a virtio-mmio device at the scratch disk's base beside a RAM upper, of a `--` after a space, after `à` and after a vertical tab, whatever parameter precedes it, and of an unclosed quote. `cold_share_command_lines_fit_the_kernel_budget_to_the_byte` takes the CLI's tokens and budget, and pins the tokens of a read-write export. `starts_refuse_the_kernel_tokens_of_the_sandbox_profile_and_of_its_mounts` adds a `--`, which a start refuses before it launches anything, as it refuses the reserved tokens. Part of #1120 (SL6.0f). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-0f-cli-command-line
branch
from
November 12, 2026 10:15
93469a4 to
b06d52f
Compare
Pedro Henrique Penna (ppenna)
marked this pull request as ready for review
November 12, 2026 10:15
Pedro Henrique Penna (ppenna)
marked this pull request as draft
November 12, 2026 10:17
Pedro Henrique Penna (ppenna)
marked this pull request as ready for review
November 12, 2026 10:18
Pedro Henrique Penna (ppenna)
merged commit Nov 12, 2026
230a1b0
into
feature/nvx-refactor
106 of 126 checks passed
Pedro Henrique Penna (ppenna)
deleted the
agents/slim-sl6-0f-cli-command-line
branch
November 12, 2026 10:32
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.

Part of #1120: SL6.0f, the CLI checks the command line that it launches. It prepares SL6.3 (#1122), which then deletes the old config types whole and stays leaving-code-only (decisions D2 and D3 on #1122).
What and why
sandbox startandsandbox runrefused a user's--cmdlinethrough the old launch profile ofhost::sandbox:check_command_line, insandbox/lifecycle/start.rssince SL3.10d (#1503), built aSandboxLaunchof the record with aSandboxUpperandSandboxSettings, bound its plan to the distro binding, and rendered the plan's kernel command line. That is not the line that a start or a run launches: it put the user's text first, thennvx_sandbox=1, the root's tokens,nvx_entrypoint=andnvx_hostname=, and it left out the view's and the managed lifecycle's tokens.nvx-rs runchecked its shares against the kernel's budget withhost::sandbox::SANDBOX_COMMAND_LINE_MAX_SIZEandmount::export_command_line_fragment. These were the CLI's last uses of the old launch, which #1503 left for later slices.Now both check the line that they launch, the one that
Config::vm_config'sVmConfig::kernel_command_linerenders: the root's and the view's tokens,nvx_maps=,nvx_sandbox=1 nvx_mode=managed nvx_identity=UID:GID, then the user's text, as given.check_command_line(config, vm)refuses, in this order and withunsupported:nvx_*ornvx-*, or that--mountowns,virtfs_*orvirtfs-*, as Linux (cmdline::parameters) or the guest's init (cmdline::init_tokens) reads it, with the old messages;host::config::COMMAND_LINE_BUDGET, the same 1024 bytes asSANDBOX_COMMAND_LINE_MAX_SIZE(2048 − 1024), with the old message;RootLayout::parserefuses, such as one with a virtio-mmio device at the scratch disk's base beside a RAM upper, with the old message;--or an unclosed quote as Linux reads them, which would hide the tokens that OpenVMM appends after it. The check appendsnvx_appended, a parameter that the user's text cannot name, since itsnvx_*tokens are refused first, and requires Linux to read it last.export_tokens, incli/sandbox/mod.rs, renders the bootstrap tokens of an export at/run/nvx/hostfs/root, asexport_command_line_fragmentrendered them, for both checks.cli/run.rschecks its budget with it andCOMMAND_LINE_BUDGET, with the same arithmetic and message.Config::hostnameloses its last caller, the old check, and goes.What changes for a user, on purpose:
--cmdlinehas that much less room beforesandbox startorsandbox runrefuses it. The old check let such a line exceed NVX's 1024 bytes of the kernel's command line.sandbox kernel command line hides the tokens that OpenVMM appends to it, where it said... hides the boot tokens of its root. It also catches a--after a byte that only Linux takes for whitespace, such as the 0xa0 that endsà, whichVmConfig's control-console check, splitting at ASCII whitespace, misses.nvx-rs run, which this does not change, still accepts such a line.VmConfigbefore it checks the command line, so a record thatConfig::vm_configrefuses, which only an editedconfig.jsoncan be, reports that before a missing artifact.Closed double quotes stay refused as before: by
VmConfig::check_command_line, whichsandbox runalready called before its launch, and by a start when it creates its VM.Docs:
doc/usage.md's--cmdlinerow anddoc/run.md's single-workload sandbox section say how--cmdlineis checked. They still said that quoted values keep their whitespace and that a--or a quote hides the root's tokens.Size. 86 core lines, 4 counted files:
sandbox/lifecycle/start.rs65,sandbox/mod.rs13,run.rs8, andsandbox/state.rs0, which only losesConfig::hostname. The estimate was 50–80 lines in 2–3 files, with a stop at 160 lines or 5 files. The public API,BOOT_CONTRACT_VERSIONandCONTROL_CONTRACT_REVISIONdo not change.Stack. Based on
feature/nvx-refactorff15032cdc5. One commit,b06d52fa085. SL6.3 (#1530) is stacked on this branch.Case matrix. No row of
doc/acceptance-case-matrix.mdlists a test that this changes or names one as coverage, and the new test belongs to none of its inventoried sets.Validation
93469a4aca7, this commit before its rebase ontoff15032cdc5:cargo fmt --check; Clippy with-D warningsfor every feature set of check-nvx-rs, for Windows andx86_64-unknown-linux-gnu, andcargo check --all-targets --all-features --target aarch64-apple-darwin;cargo doc --no-deps --all-featureswith-D warnings;public_api.py;check_test_layout.py93469a4aca7:cargo test --all-features,cargo test,cargo test --lib --no-default-featurescli111; 14 suites, 921 tests (default), with lib 853; lib 246 (no default features)93469a4aca7:cargo test --all-features --lib -- host::cli,cargo test --all-features --test cli;nvx.py test-microvm --backend kvmwithsandbox-lifecycle,sandbox-ram-upperandmanaged-exec-configcli120; the scenarios withnvx-rsbuilt at that commit and the artifacts of the last row604d8dacccb, which carries this commit unchanged:cargo test --all-features,cargo test, Clippy--all-targets --all-features;nvx.py test-microvm --backend mshvwithsandbox-lifecycle,sandbox-ram-upper,managed-exec-config,workload-identityandmanaged-lifecycleaaa542897cb, this commit before its fix on385192f3708:cargo test --all-features --no-fail-fastguest::test that fails alike at the base385192f3708(2296 passed and the same 28 failed, compared by name);cli120 and every other target passedaaa542897cb, also:nvx.py test-microvm --backend kvmwithsandbox-lifecycle,sandbox-ram-upper,sandbox-gpt-layer,sandbox-proxy-only,sandbox-blocks,managed-exec-config,snapshot-coreandfilesystem-sharesnvx-rsbuilt at that commit; OpenVMM, the kernel, the Alpine initramfs, and the Ubuntu distro layer and scratch template of CI run 43168368915 at385192f3708, checked by SHA-256A code review found that a
--afterà, which only Linux splits off, would have passed the first version of the check; the hiding refusal now catches it, with a test. Copilot's review found that the next version, which appendedxand required Linux to read it last, took a user'sxbefore a--for it, as inx\v--; the check now appendsnvx_appended, which the user's text cannot hold, and the test addsx --andx\v--, which the previous version accepted.The rebases onto
c642f09e5ed, which deletes the old clone path, and ontof03c21c3f0c, with SL6.1 (#1520), SL6.12 (#1525, #1527) and the slices before them, touch none of these files and changed nothing of this commit (same patch-id). The fix of Copilot's thread came after them. The rebase ontoff15032cdc5, with SL3.7c (#1502), SL6.11a (#1506), SL6.11c (#1504) and SL3.11a (#1512), changed nothing of this commit either (git range-diff); on it, Clippy--all-targets --all-featureswith-D warningsfor Windows andx86_64-unknown-linux-gnu, the lib'shost::clitests (229) andcli(111),check_test_layout.pyandpublic_api.pypassed on Windows.CI runs the remaining gates, MSHV and WHP among them.
Tests modified
check_test_changes.py --base origin/feature/nvx-refactorlists 2 changes to existing tests and 1 new test:starts_check_the_kernel_command_line_that_they_launch(sandbox/lifecycle/start/tests.rs) fills the 1024-byte budget to the byte with and without shares, read-only or read-write, over scratch and in RAM, and refuses one byte more with the old message. It pins the tokens of a read-only export, and the refusals of a NUL, of a virtio-mmio device at the scratch disk's base beside a RAM upper, of a--after a space, afteràand after a vertical tab, whatever parameter precedes it, and of an unclosed quote.cold_share_command_lines_fit_the_kernel_budget_to_the_byte(run/tests.rs) takesexport_tokensandCOMMAND_LINE_BUDGETin place of the old plan'sexport_command_line_fragmentandSANDBOX_COMMAND_LINE_MAX_SIZE, and pins the tokens of a read-write export, so thatnvx-rs run's budget is checked to the same byte.starts_refuse_the_kernel_tokens_of_the_sandbox_profile_and_of_its_mounts(tests/cli/lifecycle.rs) addsquiet -- debug, which a start refuses with the hiding message before it launches anything, without changing the state directory, as it refuses the reserved tokens.