Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions doc/acceptance-case-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The adapter's README said what each proved.
| `a_run_refuses_a_selection_that_names_no_template_once_its_preflight_staged_the_images` | rewritten | Images that OpenVMM cannot attach are refused before anything: `nvx-rs/src/host/config/tests.rs::cold_boot_arguments_refuse_non_raw_block_extensions`; `nvx-rs/src/host/config/tests.rs::cold_boot_arguments_refuse_disk_syntax_in_image_and_scratch_paths`. Template selections and leases retire (#1121) |
| `a_start_refuses_a_generation_that_the_template_store_does_not_hold_before_anything_else` | retired | Template generations leave with the old clone path (#1121) |
| `a_start_refuses_a_network_that_the_plan_refuses_before_anything_else` | rewritten | `nvx-rs/tests/cli.rs::network_policies_that_the_planner_refuses_fail_before_launch` |
| `a_start_refuses_shares_that_it_cannot_export_before_anything_else` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::read_only_paths_inside_read_write_directories_are_refused`; `nvx-rs/tests/security_checklist.rs::an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves` |
| `a_start_refuses_shares_that_it_cannot_export_before_anything_else` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::read_only_paths_inside_read_write_directories_are_refused`; `nvx-rs/src/host/filesystem/tests.rs::an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves` |
| `the_host_program_refuses_options_that_do_not_make_a_run` | retired | The command line and statuses of the adapter's `run` |
| `the_host_program_refuses_options_that_do_not_make_a_start` | retired | The command line and statuses of the adapter's `start` |

Expand Down Expand Up @@ -126,7 +126,7 @@ The adapter's README said what each proved.
| `a_launch_reads_only_the_networks_that_the_plan_takes` | rewritten | `nvx-rs/tests/cli.rs::network_policies_that_the_planner_refuses_fail_before_launch`; `nvx-rs/src/host/network/tests.rs::invalid_rules_are_rejected_with_the_policy_compilers_messages` |
| `a_launch_records_what_it_launched` | retired | The adapter's launch records. Callers keep `SavedVm`: `nvx-rs/src/host/vm/tests/reattach.rs::verifying_saved_values_checks_runtime_and_process_without_opening_an_endpoint` |
| `a_launch_refuses_images_that_are_not_staged_or_changed_since` | rewritten | `nvx-rs/src/host/sandbox/distro/tests.rs::a_staged_image_that_was_replaced_fails_its_check`; `nvx-rs/src/host/sandbox/scratch/tests.rs::checks_fail_without_reading_when_the_image_changes`; `nvx-rs/tests/cli.rs::start_refuses_a_configuration_without_a_valid_distro_binding` |
| `a_launch_refuses_shares_that_it_cannot_export` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::policy_paths_hide_show_and_narrow_writes`; `nvx-rs/tests/security_checklist.rs::an_export_refuses_a_read_only_path_inside_a_writable_directory` |
| `a_launch_refuses_shares_that_it_cannot_export` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::policy_paths_hide_show_and_narrow_writes`; `nvx-rs/src/host/filesystem/tests.rs::an_export_refuses_a_read_only_path_inside_a_writable_directory` |
| `a_launch_renders_each_element_of_its_network_through_the_plan` | rewritten | `nvx-rs/src/host/config/tests.rs::cold_boot_arguments_lower_layered_roots_networks_and_exports_by_path`; `nvx-rs/src/host/network/tests.rs::proxy_urls_name_the_gateway_as_the_guest_sees_it` |
| `a_launch_shares_host_paths_inside_the_authorized_directories` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::policy_paths_hide_show_and_narrow_writes`; `nvx-rs/src/host/config/tests.rs::cold_boot_arguments_lower_layered_roots_networks_and_exports_by_path` |
| `a_layered_launch_hands_openvmm_the_checked_images` | rewritten | `nvx-rs/src/host/config/tests.rs::cold_boot_arguments_lower_layered_roots_networks_and_exports_by_path`. A launch names its images by path: the checked-file handoff leaves (SL6.3, #1122), as `images_replaced_after_the_checks_never_reach_the_vm` says |
Expand All @@ -136,7 +136,7 @@ The adapter's README said what each proved.
| `shares_read_their_host_path_their_target_and_their_access` | rewritten | `nvx-rs/src/host/cli/run/guest_tokens/tests.rs::planned_boot_shares_keep_table_sources_targets_access_and_file_kind` |
| `the_host_program_refuses_a_network_before_it_launches` | rewritten | `nvx-rs/tests/cli.rs::network_policies_that_the_planner_refuses_fail_before_launch` |
| `the_host_program_refuses_options_that_do_not_make_a_command` | retired | The adapter's command lines and usage statuses |
| `the_host_program_refuses_shares_before_it_touches_the_store` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::read_only_paths_inside_read_write_directories_are_refused`; `nvx-rs/tests/security_checklist.rs::an_export_refuses_a_read_only_path_inside_a_writable_directory` |
| `the_host_program_refuses_shares_before_it_touches_the_store` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::read_only_paths_inside_read_write_directories_are_refused`; `nvx-rs/src/host/filesystem/tests.rs::an_export_refuses_a_read_only_path_inside_a_writable_directory` |
| `the_record_of_a_launch_gives_back_its_plan` | retired | The adapter's launch record and its reader |

### `vm_restart` (3)
Expand Down Expand Up @@ -164,10 +164,10 @@ The adapter's README said what each proved.
| `a_failed_mapping_tears_the_vm_down` | rewritten | The guest's refusal, which keeps the mappings before it, latches the table and refuses the start: `nvx-rs/src/guest/mappings/table/tests.rs::a_failed_mapping_keeps_those_before_it_and_latches_the_table`; `nvx-rs/src/guest/managed_agent/dispatch/tests.rs::a_failed_mapping_keeps_refusing_workloads_through_dispatch`. The stop that the guest confirms, with a successful outcome and no record of the VM: `nvx-rs/tests/cli.rs::a_mapping_that_the_guest_refuses_leaves_no_usable_start`. The teardown of the root and its mappings: `nvx-rs/src/guest/root/tests.rs::a_teardown_unmounts_the_layers_top_first_and_reports_every_failure`; `nvx-rs/src/guest/mappings/mapper/tests/privileged.rs::a_teardown_unmounts_each_mapping_and_reports_a_busy_one` |
| `a_forward_reaches_its_guest_port` | rewritten | `test-microvm --scenario host-loopback-policy` |
| `a_proxy_only_network_lets_only_its_proxy_through` | rewritten | `test-microvm --scenario sandbox-proxy-only` |
| `a_read_only_share_inside_a_writable_one_is_refused_before_launch` | rewritten | `nvx-rs/tests/security_checklist.rs::an_export_refuses_a_read_only_path_inside_a_writable_directory` |
| `a_read_only_share_inside_a_writable_one_is_refused_before_launch` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::an_export_refuses_a_read_only_path_inside_a_writable_directory` |
| `a_replaced_scratch_is_refused_before_spawn` | rewritten | `nvx-rs/src/host/sandbox/scratch/tests.rs::a_scratch_image_is_claimed_by_one_launch_and_checked_again_after_a_release`; `nvx-rs/tests/cli.rs::start_refuses_a_configuration_without_a_valid_scratch_binding` |
| `a_share_inside_a_reserved_tree_is_refused_before_launch` | rewritten | `nvx-rs/tests/security_checklist.rs::an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves`; `nvx-rs/src/host/filesystem/tests.rs::reserved_targets_depend_on_the_root` |
| `a_share_over_a_reserved_tree_is_refused_before_launch` | rewritten | `nvx-rs/tests/security_checklist.rs::an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves`; `nvx-rs/src/host/filesystem/tests.rs::reserved_targets_depend_on_the_root` |
| `a_share_inside_a_reserved_tree_is_refused_before_launch` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves`; `nvx-rs/src/host/filesystem/tests.rs::reserved_targets_depend_on_the_root` |
| `a_share_over_a_reserved_tree_is_refused_before_launch` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves`; `nvx-rs/src/host/filesystem/tests.rs::reserved_targets_depend_on_the_root` |
| `accountless_workload_identity_fails_its_stage` | rewritten | `test-microvm --scenario workload-identity`; `nvx-rs/src/guest/init/boot/tests.rs::account_creation_replaces_only_the_requested_unusable_identity_once` |
| `allowed_host_loopback_publishes_the_listeners` | rewritten | `test-microvm --scenario host-loopback-policy` |
| `an_allow_rule_lets_only_its_destination_through` | rewritten | `test-microvm --scenario l3-l4-egress-policy`; `nvx-rs/src/host/network/policy/tests/properties.rs::policies_lower_to_canonical_rules_that_match_exactly` |
Expand Down Expand Up @@ -242,7 +242,7 @@ The adapter's README said what each proved.
| `a_run_whose_clone_does_not_start_runs_nothing` | retired | Template selections and the template's `run` leave with the old clone path (#1121) |
| `a_run_whose_clone_s_vm_exits_during_its_execution_ends_with_the_clone_s_failure` | retired | The template's `run`, clone records and leases leave with the old clone path (#1121) |
| `a_selection_that_names_no_template_leases_nothing` | retired | Template selections and leases leave with the old clone path (#1121) |
| `a_start_refuses_an_export_whose_mapped_objects_changed_before_any_vmm_starts` | rewritten | `nvx-rs/tests/security_checklist.rs::an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start`; `nvx-rs/src/host/filesystem/tests.rs::swapped_objects_fail_verification` |
| `a_start_refuses_an_export_whose_mapped_objects_changed_before_any_vmm_starts` | rewritten | `nvx-rs/src/host/filesystem/tests.rs::an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start`; `nvx-rs/src/host/filesystem/tests.rs::swapped_objects_fail_verification` |
| `a_start_refuses_what_the_template_cannot_serve_before_any_vmm_starts` | rewritten | `nvx-rs/src/host/snapshot/tests.rs::snapshot_accepts_refuses_an_image_longer_than_its_placeholder`; `nvx-rs/src/host/snapshot/tests.rs::snapshot_accepts_refuses_each_scratch_geometry_mismatch`; `nvx-rs/src/host/snapshot/tests.rs::snapshot_accepts_refuses_each_memory_mismatch_without_rounding_or_overflow` |
| `a_template_without_a_nic_serves_clones_without_a_network` | rewritten | `nvx-rs/src/host/snapshot/tests.rs::snapshot_accepts_refuses_both_nic_presence_mismatches_and_each_named_address_mismatch` |
| `a_tombstone_leaves_the_running_clone_of_its_generation_to_its_lease` | retired | Tombstones, generations and leases leave with the old clone path (#1121) |
Expand Down
43 changes: 23 additions & 20 deletions nvx-rs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ changes only when the module's purpose does.
| [`nvx::host::config`](#nvxhostconfig) | `VmConfig` and `CaptureConfig`: pure configuration, cold-boot kernel/OpenVMM arguments, portable length checks, and capture identity |
| [`nvx::host::restore`](#nvxhostrestore) | A caller-driven restore to Ready without I/O or a clock, and its peer-verified restore-ready listener |
| [`nvx::host::network`](#nvxhostnetwork) | The one lowering of a network posture into OpenVMM options, for the CLI and external orchestrators |
| [`nvx::host::filesystem`](#nvxhostfilesystem) | The planner of the host paths that every NVX caller exports to the guest through OpenVMM's virtio-fs device |
| [`nvx::host::filesystem`](#nvxhostfilesystem) | The plan of the host paths that a VM exports to the guest through OpenVMM's virtio-fs device, its check and lowering, and the guest-path convention |
| [`nvx::host::nvxs`](#nvxhostnvxs) | Compatibility paths for the host NVXS connection and its retained cause details |
| [`nvx::host::transport`](#nvxhosttransport) | A verified VM endpoint connection and the blocking host NVXS driver, with the existing timed transport |
| [`nvx::host::process`](#nvxhostprocess) | Verified references to OpenVMM processes, through which callers wait for them and end them |
Expand All @@ -136,8 +136,7 @@ layer whose superblock requests recovery, before mounting anything. This
policy does not change EROFS layers or writable ext4 scratches.

Lowering functions take the names by which messages refer to their inputs, such
as `EgressRules::name` and `PathList::name`, so callers' messages name their own
fields.
as `EgressRules::name`, so callers' messages name their own fields.

### `nvx::protocol`

Expand Down Expand Up @@ -936,14 +935,18 @@ action that needs more than 256 rules.

### `nvx::host::filesystem`

The planner of every NVX caller: `plan` turns an `ExportRequest`, the mapped
host paths at their guest targets, their denied, allowed, and write paths, and
the owner, into the `ExportPlan` of host paths through OpenVMM's aggregate
virtio-fs device, for a root's `ReservedTargets`, the blockless root's or the
container root's: its children, its ordered binds, which give the host-mapping
table, and the identities that each start checks again; and `guest_path` (also
at `nvx::`), the guest path at which the host-path convention places a resolved
host path.
The `ExportPlan` of host paths through OpenVMM's aggregate virtio-fs device, for
a root's `ReservedTargets`, the blockless root's or the container root's: its
children, its ordered binds, which give the host-mapping table, and the
identities that each start checks again; `ExportPlan::check`, which checks a
recorded plan without reading the host, and the plan's OpenVMM options, boot
token, and mapping table; and `guest_path` (also at `nvx::`), the guest path at
which the host-path convention places a resolved host path.

The planner, which turns the mapped host paths at their guest targets, their
denied, allowed, and write paths, and the owner into a plan, and the checks of a
plan's host objects before each start are the CLI's path rules, private to the
crate (feature `cli`).

### `nvx::host::nvxs`

Expand Down Expand Up @@ -1511,15 +1514,15 @@ which only the CLI uses (feature `cli`), but for the block geometry that
`nvx::host::vm` and `nvx::host::snapshot` read and the tag of the shares'
virtio-fs device, which a snapshot's key names: the workload identity that
`--workload-user` names; the live shares of `--mount`, their guest targets and
the reserved ones, their access policies and owner, and the checks of their
host paths, which it plans through `nvx::host::filesystem` for the container
root; and the checks that `nvx-rs sandbox` and `nvx-rs run` apply to their
options: the attribution of `--mount-deny`, `--mount-allow`, and `--mount-write`
to shares, the systemd entrypoint check and the explicit verification of the
distro layer, the targets of `nvx-rs run` shares, and the managed exec
environment. Its image staging, the `layer`, the `distro` and `scratch`
bindings, and the seals of the private `host::seal` that they record, is
described in [Distro bindings](#distro-bindings) and
the reserved ones, their access policies and owner, and the checks of their host
paths, which it plans through the private planner of `nvx::host::filesystem` for
the container root; and the checks that `nvx-rs sandbox` and `nvx-rs run` apply
to their options: the attribution of `--mount-deny`, `--mount-allow`, and
`--mount-write` to shares, the systemd entrypoint check and the explicit
verification of the distro layer, the targets of `nvx-rs run` shares, and the
managed exec environment. Its image staging, the `layer`, the `distro` and
`scratch` bindings, and the seals of the private `host::seal` that they record,
is described in [Distro bindings](#distro-bindings) and
[Images by path](#images-by-path).

The sandbox launch profile specifies its own inputs rather than emulating Python.
Expand Down
20 changes: 0 additions & 20 deletions nvx-rs/public-api/linux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -963,42 +963,22 @@ method nvx::host::filesystem::ExportPlan::guest_table
method nvx::host::filesystem::ExportPlan::kernel_token
method nvx::host::filesystem::ExportPlan::openvmm_arguments
field nvx::host::filesystem::ExportPlan::owner
method nvx::host::filesystem::ExportPlan::verify
struct nvx::host::filesystem::ExportRequest
field nvx::host::filesystem::ExportRequest::allowed
field nvx::host::filesystem::ExportRequest::denied
field nvx::host::filesystem::ExportRequest::mappings
field nvx::host::filesystem::ExportRequest::owner
field nvx::host::filesystem::ExportRequest::reserved
field nvx::host::filesystem::ExportRequest::write
struct nvx::host::filesystem::FileIdentity
field nvx::host::filesystem::FileIdentity::device
field nvx::host::filesystem::FileIdentity::index
const nvx::host::filesystem::GUEST_EXPORT
const nvx::host::filesystem::MAX_CHILDREN
struct nvx::host::filesystem::Mapping
field nvx::host::filesystem::Mapping::name
field nvx::host::filesystem::Mapping::path
field nvx::host::filesystem::Mapping::read_only
field nvx::host::filesystem::Mapping::target
enum nvx::host::filesystem::Owner
variant nvx::host::filesystem::Owner::Caller
variant nvx::host::filesystem::Owner::Vmm
struct nvx::host::filesystem::PathList
field nvx::host::filesystem::PathList::name
field nvx::host::filesystem::PathList::paths
const nvx::host::filesystem::RESERVED_TARGETS
struct nvx::host::filesystem::ReservedTargets
const nvx::host::filesystem::ReservedTargets::BLOCKLESS_ROOT
const nvx::host::filesystem::ReservedTargets::CONTAINER_ROOT
field nvx::host::filesystem::ReservedTargets::exact
method nvx::host::filesystem::ReservedTargets::reservation
field nvx::host::filesystem::ReservedTargets::trees
enum nvx::host::filesystem::Target
variant nvx::host::filesystem::Target::Guest
field nvx::host::filesystem::Target::Guest::0
fn nvx::host::filesystem::guest_path
fn nvx::host::filesystem::plan
mod nvx::host::network
enum nvx::host::network::Access
variant nvx::host::network::Access::Allow
Expand Down
20 changes: 0 additions & 20 deletions nvx-rs/public-api/windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -421,42 +421,22 @@ method nvx::host::filesystem::ExportPlan::guest_table
method nvx::host::filesystem::ExportPlan::kernel_token
method nvx::host::filesystem::ExportPlan::openvmm_arguments
field nvx::host::filesystem::ExportPlan::owner
method nvx::host::filesystem::ExportPlan::verify
struct nvx::host::filesystem::ExportRequest
field nvx::host::filesystem::ExportRequest::allowed
field nvx::host::filesystem::ExportRequest::denied
field nvx::host::filesystem::ExportRequest::mappings
field nvx::host::filesystem::ExportRequest::owner
field nvx::host::filesystem::ExportRequest::reserved
field nvx::host::filesystem::ExportRequest::write
struct nvx::host::filesystem::FileIdentity
field nvx::host::filesystem::FileIdentity::device
field nvx::host::filesystem::FileIdentity::index
const nvx::host::filesystem::GUEST_EXPORT
const nvx::host::filesystem::MAX_CHILDREN
struct nvx::host::filesystem::Mapping
field nvx::host::filesystem::Mapping::name
field nvx::host::filesystem::Mapping::path
field nvx::host::filesystem::Mapping::read_only
field nvx::host::filesystem::Mapping::target
enum nvx::host::filesystem::Owner
variant nvx::host::filesystem::Owner::Caller
variant nvx::host::filesystem::Owner::Vmm
struct nvx::host::filesystem::PathList
field nvx::host::filesystem::PathList::name
field nvx::host::filesystem::PathList::paths
const nvx::host::filesystem::RESERVED_TARGETS
struct nvx::host::filesystem::ReservedTargets
const nvx::host::filesystem::ReservedTargets::BLOCKLESS_ROOT
const nvx::host::filesystem::ReservedTargets::CONTAINER_ROOT
field nvx::host::filesystem::ReservedTargets::exact
method nvx::host::filesystem::ReservedTargets::reservation
field nvx::host::filesystem::ReservedTargets::trees
enum nvx::host::filesystem::Target
variant nvx::host::filesystem::Target::Guest
field nvx::host::filesystem::Target::Guest::0
fn nvx::host::filesystem::guest_path
fn nvx::host::filesystem::plan
mod nvx::host::network
enum nvx::host::network::Access
variant nvx::host::network::Access::Allow
Expand Down
5 changes: 5 additions & 0 deletions nvx-rs/src/host/filesystem/host_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
use std::fs;
use std::path::{Path, PathBuf};

#[cfg(feature = "cli")]
use super::FileIdentity;
#[cfg(feature = "cli")]
use crate::error::{Error, Result};
#[cfg(feature = "cli")]
use crate::host::platform;
pub(crate) use crate::host::platform::is_reparse_point;

/// Returns the stable device-and-file identity of `path` for rename detection.
#[cfg(feature = "cli")]
pub(super) fn identity(path: &Path) -> Result<FileIdentity> {
platform::file_identity(path)
.map(|(device, index)| FileIdentity { device, index })
Expand Down Expand Up @@ -53,6 +57,7 @@ pub(crate) fn canonicalize(path: &Path) -> std::io::Result<PathBuf> {

/// Canonicalizes the deepest existing ancestor and appends the rest. Returns whether the
/// complete path exists.
#[cfg(feature = "cli")]
pub(super) fn canonicalize_lenient(path: &Path) -> std::io::Result<(PathBuf, bool)> {
let mut existing = path.to_path_buf();
let mut missing = Vec::new();
Expand Down
Loading
Loading