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
28 changes: 27 additions & 1 deletion nvx-rs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ changes only when the module's purpose does.
| [`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::store`](#nvxhoststore) | `SandboxStore`: the runtime records of one sandbox, which every host that supervises it shares under one lock |
| [`nvx::host::instance`](#nvxhostinstance) | `Instance`: a VM in a sandbox store of its own, which the store, the supervisor, and the control session drive |
| [`nvx::host::nvxs`](#nvxhostnvxs) | `HostConnection`: the host's role of the NVXS session over a platform transport |
| [`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 |
| [`nvx::host::supervisor`](#nvxhostsupervisor) | The supervisor of a sandbox's VMM, beneath the CLI, `Instance`, and external orchestrators |
| [`nvx::host::template`](#nvxhosttemplate) | Legacy template capture and clone plans and store, with aliases of the snapshot metadata |
Expand Down Expand Up @@ -908,13 +909,38 @@ instance creation or launch records, respectively.

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

Compatibility paths for `HostConnection` and its retained cause details, now
owned by [`nvx::host::transport`](#nvxhosttransport).

### `nvx::host::transport`

`connect_verified` opens and holds the recorded process by its boot, ID and
start time, retries while the endpoint is unavailable until the caller's
deadline, and checks its server before authentication: Unix peer credentials
and the original socket peer's live pidfd on Linux, and the named-pipe server
process ID on Windows. Linux requires `SO_PEERPIDFD` (Linux 6.5 or a backport)
and refuses unverifiable peers rather than falling back to a numeric PID.
An indeterminate process check remains an error, never exit proof.

`HostConnection`: the host's role of the NVXS session over a platform transport,
on which `nvx::host::session` and other host applications run their protocols.
It attaches with the launch capability, waiting while the broker asks it to,
sends application bytes in as many DATA records as they take, and returns each
DATA payload from the guest, with deadlines; a receive that times out keeps a
partial record.

These APIs return the crate's `Result`: a deadline is `TimedOut`, an exited
recorded VM `Exited`, a refused, closed, reset or broken session `Protocol`,
and another transport failure `Io`. Original I/O and protocol causes are
retained directly; attachment refusal, reset and ended-connection details
remain available as sources.

`Transport` and `TransportHandle` re-export the existing platform types, with
one definition beneath the OS adapters. Timed reads and writes, native-handle
duplication and `unread` are unchanged: Linux reports Unix `SIOCOUTQ` charges,
and Windows reports `None`. The old `host::session::connect` remains a
compatibility wrapper.

### `nvx::host::process`

Verified process references. A `ProcessRef` names one process by its ID, its
Expand Down
26 changes: 26 additions & 0 deletions nvx-rs/public-api/linux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3574,6 +3574,32 @@ field nvx::host::template::TimeContract::tsc_frequency_hz
field nvx::host::template::TimeContract::tsc_tolerance_ppm
fn nvx::host::template::reattach_clone
fn nvx::host::template::status_evidence
mod nvx::host::transport
struct nvx::host::transport::HostConnection
method nvx::host::transport::HostConnection::attach
method nvx::host::transport::HostConnection::identity
method nvx::host::transport::HostConnection::receive
method nvx::host::transport::HostConnection::send
method nvx::host::transport::HostConnection::session
enum nvx::host::transport::HostConnectionError
variant nvx::host::transport::HostConnectionError::Closed
variant nvx::host::transport::HostConnectionError::Ended
variant nvx::host::transport::HostConnectionError::Io
field nvx::host::transport::HostConnectionError::Io::0
variant nvx::host::transport::HostConnectionError::Protocol
field nvx::host::transport::HostConnectionError::Protocol::0
variant nvx::host::transport::HostConnectionError::Rejected
field nvx::host::transport::HostConnectionError::Rejected::0
variant nvx::host::transport::HostConnectionError::Reset
field nvx::host::transport::HostConnectionError::Reset::0
variant nvx::host::transport::HostConnectionError::TimedOut
trait nvx::host::transport::Transport
method nvx::host::transport::Transport::read
method nvx::host::transport::Transport::try_clone_handle
method nvx::host::transport::Transport::unread
method nvx::host::transport::Transport::write_all
type nvx::host::transport::TransportHandle
fn nvx::host::transport::connect_verified
mod nvx::host::vm
struct nvx::host::vm::Capability
method nvx::host::vm::Capability::as_bytes
Expand Down
26 changes: 26 additions & 0 deletions nvx-rs/public-api/windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,32 @@ field nvx::host::template::TimeContract::tsc_frequency_hz
field nvx::host::template::TimeContract::tsc_tolerance_ppm
fn nvx::host::template::reattach_clone
fn nvx::host::template::status_evidence
mod nvx::host::transport
struct nvx::host::transport::HostConnection
method nvx::host::transport::HostConnection::attach
method nvx::host::transport::HostConnection::identity
method nvx::host::transport::HostConnection::receive
method nvx::host::transport::HostConnection::send
method nvx::host::transport::HostConnection::session
enum nvx::host::transport::HostConnectionError
variant nvx::host::transport::HostConnectionError::Closed
variant nvx::host::transport::HostConnectionError::Ended
variant nvx::host::transport::HostConnectionError::Io
field nvx::host::transport::HostConnectionError::Io::0
variant nvx::host::transport::HostConnectionError::Protocol
field nvx::host::transport::HostConnectionError::Protocol::0
variant nvx::host::transport::HostConnectionError::Rejected
field nvx::host::transport::HostConnectionError::Rejected::0
variant nvx::host::transport::HostConnectionError::Reset
field nvx::host::transport::HostConnectionError::Reset::0
variant nvx::host::transport::HostConnectionError::TimedOut
trait nvx::host::transport::Transport
method nvx::host::transport::Transport::read
method nvx::host::transport::Transport::try_clone_handle
method nvx::host::transport::Transport::unread
method nvx::host::transport::Transport::write_all
type nvx::host::transport::TransportHandle
fn nvx::host::transport::connect_verified
mod nvx::host::vm
struct nvx::host::vm::Capability
method nvx::host::vm::Capability::as_bytes
Expand Down
12 changes: 7 additions & 5 deletions nvx-rs/src/host/cli/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
//!
//! - [`Session::connect`] retries the endpoint every 25 ms until its timeout, then attaches with
//! the capability within a fresh timeout. On Windows, it gives up at once on the errors that
//! Python does not retry.
//! Python does not retry. On Linux, unsupported peer verification fails at once, retaining
//! its diagnostic instead of reporting that the endpoint did not appear.
//! - Each operation bounds its request and its response by one timeout. A transfer that times
//! out fails with `managed control request timed out` while it sends and `managed control
//! response timed out` while it receives.
Expand Down Expand Up @@ -247,10 +248,11 @@ impl Session {
match platform::connect_endpoint(endpoint, pid, slice) {
Ok(transport) => break transport,
Err(error) => {
if cfg!(windows)
&& error
.raw_os_error()
.is_some_and(|code| raised_at_once(code as u32))
if (cfg!(target_os = "linux") && error.kind() == io::ErrorKind::Unsupported)
|| (cfg!(windows)
&& error
.raw_os_error()
.is_some_and(|code| raised_at_once(code as u32)))
{
return Err(Exit::from_os_error(error));
}
Expand Down
58 changes: 58 additions & 0 deletions nvx-rs/src/host/cli/session/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,64 @@ mod endpoints {
);
}

#[test]
#[cfg(target_os = "linux")]
fn unsupported_peer_verification_fails_without_retrying() {
use std::process::{Command, Stdio};

let child = "NVX_TEST_CLI_CONTROL_PIDFD_DENIAL";
let Some(errno) = std::env::var_os(child) else {
for errno in [nix::libc::ENOPROTOOPT, nix::libc::EPERM, nix::libc::EACCES] {
let mut command = Command::new(std::env::current_exe().unwrap());
command
.args([
"--exact",
"host::cli::session::tests::endpoints::unsupported_peer_verification_fails_without_retrying",
"--nocapture",
])
.env(child, errno.to_string())
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
crate::host::sys::tests::refuse_peer_pidfd_on_spawn(&mut command, errno);
let output = crate::host::tests::spawn_locked(&mut command)
.unwrap()
.wait_with_output()
.unwrap();
assert!(
output.status.success()
&& String::from_utf8_lossy(&output.stdout)
.contains(&format!("NVX_CLI_CONTROL_PIDFD_REFUSED {errno}")),
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
return;
};
let errno: i32 = errno.to_str().unwrap().parse().unwrap();
let directory = tempfile::tempdir().unwrap();
let path = directory.path().join("control.sock");
let _listener = UnixListener::bind(&path).unwrap();
let mut checks = 0;
let failure = Session::connect_unless_exited(
path.to_str().unwrap(),
std::process::id(),
&CAPABILITY,
60.0,
|| {
checks += 1;
checks == 2
},
)
.err()
.expect("unsupported peer verification must fail before authentication");
assert_eq!(failure.code(), Some(ErrorCode::Io));
assert!(failure.message().unwrap().contains("SO_PEERPIDFD"));
assert_eq!(checks, 0, "a permanent verification failure must not retry");
println!("NVX_CLI_CONTROL_PIDFD_REFUSED {errno}");
}

#[test]
fn waits_for_an_endpoint_end_once_openvmm_exits() {
let directory = tempfile::tempdir().unwrap();
Expand Down
9 changes: 5 additions & 4 deletions nvx-rs/src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
//! - [`template`] retains the legacy capture and clone plans, the [`Store`](template::Store) of
//! published generations and their leases, and aliases of the snapshot metadata. Its
//! [`TemplatePlan`](template::TemplatePlan) lowers an adapter's plan for a capture.
//! - [`session`] speaks NVX's control protocol, `NVXC`, over [`nvxs`], which runs the host's role
//! of the NVXS session for it and for any other application protocol, over a platform
//! transport. [`platform`] holds the primitives of Linux and Windows hosts. Other hosts compile
//! but report NVX as unavailable.
//! - [`session`] speaks NVX's control protocol, `NVXC`, over [`transport`], which verifies a VM's
//! endpoint and runs the host's role of the NVXS session for it and for any other application
//! protocol, over a platform transport. [`nvxs`] retains compatibility paths. [`platform`] holds
//! the primitives of Linux and Windows hosts. Other hosts compile but report NVX as unavailable.
//! - [`process`] names processes by verified references: their ID, start time, and host boot,
//! through which a pidfd or a process handle holds them, so that waits sleep until a process
//! exits and termination reaches only it, whether or not the caller started it.
Expand Down Expand Up @@ -103,4 +103,5 @@ mod sys;
pub mod template;
#[cfg(test)]
pub(crate) mod tests;
pub mod transport;
pub mod vm;
Loading
Loading