#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct VerifiedStateAnchorReadiness { staged: StagedProcessOwnership, mount: MountIdentity, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct StateAnchorAcquisition<'path> { pub lower: &'path Path, pub expected_lower: (u64, u64), pub expected_parent: lazaret_core::identity::PidfsProcessIdentityV1, pub ownership: ProcessOwnershipContext, } pub struct StateAnchorLaunchAuthority { lower: OwnedFd, lower_label: PathBuf, persistent_root: OwnedFd, persistent_anchor: OwnedFd, persistent_anchor_label: PathBuf, runtime_root: OwnedFd, runtime_anchor: OwnedFd, runtime_anchor_label: PathBuf, expected_lower: (u64, u64), persistent_destinations: Vec, } impl StateAnchorLaunchAuthority { /// Captures exact directory authorities for inheritance by the Runtime Supervisor. /// /// # Errors /// Refuses a changed layout or prepared lower. pub fn capture( layout: &StateAnchorLayout<'_>, artifact: &PreparedArtifact, ) -> Result { layout.revalidate()?; let expected_lower = (artifact.device.get(), artifact.inode.get()); let lower = open_exact_directory_path(&path_from_host(&artifact.path), expected_lower)?; Self::capture_open( layout, expected_lower, path_from_host(&artifact.path), lower, ) } /// Captures an already-confined prepared-lower authority for inheritance. /// /// # Errors /// Refuses a changed layout or prepared-lower descriptor. pub fn capture_retained( layout: &StateAnchorLayout<'_>, artifact: &PreparedArtifact, lower_label: &Path, lower: impl AsFd, ) -> Result { layout.revalidate()?; let expected_lower = (artifact.device.get(), artifact.inode.get()); require_directory_descriptor_identity(&lower, expected_lower)?; Self::capture_open(layout, expected_lower, lower_label.to_owned(), lower) } fn capture_open( layout: &StateAnchorLayout<'_>, expected_lower: (u64, u64), lower_label: PathBuf, lower: impl AsFd, ) -> Result { Ok(Self { lower: inherit_for_exec(lower)?, lower_label, persistent_root: inherit_for_exec(&layout.persistent_root)?, persistent_anchor: inherit_for_exec(&layout.persistent_anchor)?, persistent_anchor_label: layout .upper_label .parent() .ok_or(StateAnchorError::InvalidLayout( "upper label has no State Anchor parent", ))? .to_owned(), runtime_root: inherit_for_exec(&layout.runtime_root)?, runtime_anchor: inherit_for_exec(&layout.runtime_anchor)?, runtime_anchor_label: layout .merged_label .parent() .ok_or(StateAnchorError::InvalidLayout( "merged label has no State Anchor parent", ))? .to_owned(), expected_lower, persistent_destinations: layout.persistent_destinations.clone(), }) } #[must_use] pub fn lower_fd(&self) -> i32 { self.lower.as_raw_fd() } #[must_use] pub fn persistent_anchor_fd(&self) -> i32 { self.persistent_anchor.as_raw_fd() } #[must_use] pub fn persistent_root_fd(&self) -> i32 { self.persistent_root.as_raw_fd() } #[must_use] pub fn runtime_anchor_fd(&self) -> i32 { self.runtime_anchor.as_raw_fd() } #[must_use] pub fn runtime_root_fd(&self) -> i32 { self.runtime_root.as_raw_fd() } #[must_use] pub fn runtime_anchor_label(&self) -> &Path { &self.runtime_anchor_label } #[must_use] pub fn lower_label(&self) -> &Path { &self.lower_label } #[must_use] pub fn persistent_anchor_label(&self) -> &Path { &self.persistent_anchor_label } #[must_use] pub const fn expected_lower(&self) -> (u64, u64) { self.expected_lower } #[must_use] pub fn persistent_destinations(&self) -> &[PathBuf] { &self.persistent_destinations } } pub struct RuntimeStateAnchorAuthority { lower: OwnedFd, persistent_anchor: OwnedFd, runtime_anchor: OwnedFd, merged_label: PathBuf, merged_descriptor: OwnedFd, } #[derive(Clone, Copy)] pub struct RuntimeStateAnchorInherited<'a> { pub lower_fd: i32, pub lower_label: &'a Path, pub persistent_root_fd: i32, pub persistent_anchor_fd: i32, pub persistent_anchor_label: &'a Path, pub runtime_root_fd: i32, pub runtime_anchor_fd: i32, pub runtime_anchor_label: &'a Path, pub expected_lower: (u64, u64), } impl RuntimeStateAnchorAuthority { /// Reopens inherited authorities without falling back to ambient configured paths. /// /// # Errors /// Refuses missing, replaced, or incorrectly typed descriptors and fixed children. pub fn from_inherited( inherited: RuntimeStateAnchorInherited<'_>, ) -> Result { let retained_lower = reopen_inherited_directory(inherited.lower_fd)?; require_directory_descriptor_identity(&retained_lower, inherited.expected_lower)?; if !inherited.lower_label.is_absolute() { return Err(StateAnchorError::InvalidLayout( "prepared lower label is not absolute", )); } let lower = open_exact_directory_path(inherited.lower_label, inherited.expected_lower)?; let persistent_root = reopen_inherited_directory(inherited.persistent_root_fd)?; let retained_persistent_anchor = reopen_inherited_directory(inherited.persistent_anchor_fd)?; if !inherited.persistent_anchor_label.is_absolute() { return Err(StateAnchorError::InvalidLayout( "persistent State Anchor label is not absolute", )); } let retained_persistent = rustix::fs::fstat(&retained_persistent_anchor).map_err(io::Error::from)?; let confined_persistent_anchor = open_directory(&persistent_root, Path::new("state-anchor"))?; require_directory_descriptor_identity( &confined_persistent_anchor, (retained_persistent.st_dev, retained_persistent.st_ino), )?; let persistent_anchor = open_exact_directory_path( inherited.persistent_anchor_label, (retained_persistent.st_dev, retained_persistent.st_ino), )?; let runtime_root = reopen_inherited_directory(inherited.runtime_root_fd)?; let retained_runtime_anchor = reopen_inherited_directory(inherited.runtime_anchor_fd)?; if !inherited.runtime_anchor_label.is_absolute() { return Err(StateAnchorError::InvalidLayout( "runtime State Anchor label is not absolute", )); } let confined_runtime_anchor = open_directory(&runtime_root, Path::new("state-anchor"))?; let retained = rustix::fs::fstat(&retained_runtime_anchor).map_err(io::Error::from)?; require_directory_descriptor_identity( &confined_runtime_anchor, (retained.st_dev, retained.st_ino), )?; let runtime_anchor = open_exact_directory_path( inherited.runtime_anchor_label, (retained.st_dev, retained.st_ino), )?; for name in ["upper", "work"] { drop(open_directory(&persistent_anchor, Path::new(name))?); } let merged_descriptor = open_directory(&runtime_anchor, Path::new("merged"))?; let merged_label = inherited.runtime_anchor_label.join("merged"); Ok(Self { lower, persistent_anchor, runtime_anchor, merged_label, merged_descriptor, }) } /// Mounts the exact inherited prepared lower and anchors under RS child ownership. /// /// # Errors /// Refuses acquisition, acknowledgment, readiness, or authority failures. pub fn acquire( self, expected_parent: lazaret_core::identity::PidfsProcessIdentityV1, ownership: ProcessOwnershipContext, stage: Stage, acknowledge: Acknowledge, ready: Ready, ) -> Result where Stage: FnOnce(StagedProcessOwnership) -> io::Result<()>, Acknowledge: FnOnce(StagedProcessOwnership) -> io::Result, Ready: FnOnce(VerifiedStateAnchorReadiness) -> io::Result<()>, { if ownership.slot != HostProcessOwnershipSlot::StateAnchorDaemon { return Err(StateAnchorError::InvalidLayout( "process slot is not State Anchor daemon", )); } let baseline = mount_identity(&self.merged_descriptor)?; let lower_launch = inherit_for_exec(&self.lower)?; let persistent_launch = inherit_for_exec(&self.persistent_anchor)?; let target = TargetCommand::new("fuse-overlayfs") .argument("-f") .argument("-o") .argument(overlay_options( &descriptor_path(&lower_launch), &descriptor_child_path(&persistent_launch, "upper"), &descriptor_child_path(&persistent_launch, "work"), )) .argument(&self.merged_label); let process = child_broker().acquire(expected_parent, ownership, &target, stage, acknowledge)?; let staged = StagedProcessOwnership::v1( ownership.domain_id, ownership.generation_id, ownership.coordinator_id, ownership.slot, process.identity(), ); let deadline = Instant::now() + MOUNT_TIMEOUT; loop { if process.has_exited()? { child_broker().reap(process)?; return Err(StateAnchorError::DaemonExited); } let mounted = open_mounted_directory(&self.runtime_anchor, Path::new("merged"))?; let observed = mount_identity(&mounted)?; if observed.mount_id != baseline.mount_id { let readiness = VerifiedStateAnchorReadiness { staged, mount: observed, }; if let Err(error) = ready(readiness) { process.send_signal(rustix::process::Signal::KILL)?; while !process.has_exited()? { thread::yield_now(); } let _ = rootless_unmount_path(&self.merged_label); child_broker().reap(process)?; return Err(error.into()); } return Ok(RuntimeStateAnchorMount { authority: self, process, mount: observed, merged: mounted, }); } if Instant::now() >= deadline { process.send_signal(rustix::process::Signal::KILL)?; while !process.has_exited()? { thread::yield_now(); } let merged = open_mounted_directory(&self.runtime_anchor, Path::new("merged"))?; let observed = mount_identity(&merged)?; if observed.mount_id != baseline.mount_id { let _ = rootless_unmount_path(&self.merged_label); } child_broker().reap(process)?; return Err(StateAnchorError::MountTimeout); } thread::sleep(MOUNT_POLL_INTERVAL); } } } pub struct RuntimeStateAnchorMount { authority: RuntimeStateAnchorAuthority, process: RetainedProcess, mount: MountIdentity, merged: OwnedFd, } pub struct RuntimeStateAnchorAbsenceAuthority { runtime_anchor: OwnedFd, mount: MountIdentity, } impl RuntimeStateAnchorAbsenceAuthority { /// Reopens the exact runtime anchor to produce a fresh post-unmount observation. /// /// # Errors /// Refuses an unreadable anchor or the continued presence of the retired mount. pub fn observe_absence( &self, expected_mount: MountIdentity, ) -> Result { if expected_mount != self.mount { return Err(StateAnchorError::OwnershipMismatch); } let observed = mount_identity(&open_directory(&self.runtime_anchor, Path::new("merged"))?)?; if observed == self.mount { Err(StateAnchorError::OwnershipMismatch) } else { Ok(observed) } } } impl RuntimeStateAnchorMount { #[must_use] pub const fn mount_identity(&self) -> MountIdentity { self.mount } /// Validates configured persistent subpaths beneath the exact mounted view. /// /// # Errors /// Refuses missing paths, symlinks, nested mounts, or mount replacement. pub fn require_persistent_destinations( &self, destinations: &[PathBuf], ) -> Result<(), StateAnchorError> { if mount_identity(&self.merged)? != self.mount { return Err(StateAnchorError::OwnershipMismatch); } for destination in destinations { if destination.as_os_str().is_empty() || destination .components() .any(|component| !matches!(component, std::path::Component::Normal(_))) { return Err(StateAnchorError::InvalidLayout( "persistent destination is not normalized and relative", )); } let descriptor = openat2( &self.merged, destination, OFlags::PATH | OFlags::DIRECTORY | OFlags::CLOEXEC | OFlags::NOFOLLOW, Mode::empty(), ResolveFlags::BENEATH | ResolveFlags::NO_MAGICLINKS | ResolveFlags::NO_SYMLINKS | ResolveFlags::NO_XDEV, ) .map_err(io::Error::from)?; if !FileType::from_raw_mode( rustix::fs::fstat(&descriptor) .map_err(io::Error::from)? .st_mode, ) .is_dir() { return Err(StateAnchorError::InvalidLayout( "persistent destination is not a directory", )); } } Ok(()) } /// Unmounts and reaps only the retained exact RS-owned State Anchor. /// /// # Errors /// Refuses mount replacement, unmount failure, or exact child cleanup failure. pub fn unmount(self) -> Result { let Self { authority, process, mount, merged, } = self; let observed = mount_identity(&merged)?; if observed != mount { return Err(StateAnchorError::OwnershipMismatch); } drop(merged); rootless_unmount_path(&authority.merged_label)?; let after = mount_identity(&open_directory( &authority.runtime_anchor, Path::new("merged"), )?)?; if after == mount { return Err(StateAnchorError::OwnershipMismatch); } child_broker().reap(process)?; Ok(RuntimeStateAnchorAbsenceAuthority { runtime_anchor: authority.runtime_anchor, mount, }) } } impl VerifiedStateAnchorReadiness { #[must_use] pub const fn from_parts(staged: StagedProcessOwnership, mount: MountIdentity) -> Self { Self { staged, mount } } #[must_use] pub const fn staged(self) -> StagedProcessOwnership { self.staged } #[must_use] pub const fn mount(self) -> MountIdentity { self.mount } }