Compose cold-start resources under Runtime Supervisor ownership

This commit is contained in:
ms2k 2026-07-16 17:29:23 +09:00
commit 33ac0ba4ee
2 changed files with 1827 additions and 139 deletions

View file

@ -2,13 +2,22 @@ use std::collections::BTreeMap;
use std::ffi::OsString;
use std::fs;
use std::os::unix::ffi::OsStringExt;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
use lazaret_core::configuration::{
ConfigurationLoadRequest, SandboxLayoutV1, load_trusted_configuration,
};
use lazaret_state_anchor::{ProtectedRuntimeFiles, StateAnchorLayout};
use lazaret_core::identity::{
DeviceId, HostPath, IdMapDigest, InodeId, PolicyId, PreparedArtifactId, SelectedManifestDigest,
SourceIdentity,
};
use lazaret_core::records::{ArtifactState, PreparedArtifact};
use lazaret_state_anchor::{
ProtectedRuntimeFiles, RuntimeStateAnchorAuthority, StateAnchorLaunchAuthority,
StateAnchorLayout,
};
static SEQUENCE: AtomicU64 = AtomicU64::new(0);
@ -48,6 +57,45 @@ fn replaced_runtime_root_is_refused_before_runtime_file_write() {
assert!(!replacement_files.join("hosts").exists());
}
#[test]
fn inherited_runtime_authority_accepts_only_the_exact_prepared_lower() {
let tree = TestTree::new();
let configuration = configuration(&tree);
let layout = StateAnchorLayout::create(&configuration).unwrap();
let lower = tree.path.join("prepared-lower");
fs::create_dir(&lower).unwrap();
let metadata = lower.metadata().unwrap();
let artifact = PreparedArtifact {
prepared_artifact_id: PreparedArtifactId::new([8; 32]),
source_identity: SourceIdentity::new(b"fixture".to_vec()),
selected_manifest_digest: SelectedManifestDigest::new([9; 32]),
policy_id: PolicyId::new([10; 32]),
id_map_digest: IdMapDigest::new([11; 32]),
path: HostPath::new(lower.as_os_str().as_encoded_bytes().to_vec()),
device: DeviceId::new(metadata.dev()),
inode: InodeId::new(metadata.ino()),
state: ArtifactState::Available,
};
let launch = StateAnchorLaunchAuthority::capture(&layout, &artifact).unwrap();
let expected = launch.expected_lower();
RuntimeStateAnchorAuthority::from_inherited(
launch.lower_fd(),
launch.persistent_anchor_fd(),
launch.runtime_anchor_fd(),
expected,
)
.unwrap();
assert!(
RuntimeStateAnchorAuthority::from_inherited(
launch.lower_fd(),
launch.persistent_anchor_fd(),
launch.runtime_anchor_fd(),
(expected.0, expected.1 + 1),
)
.is_err()
);
}
struct TestTree {
path: PathBuf,
}

View file

@ -19,8 +19,9 @@ use lazaret_linux::process::{
ProcessOwnershipContext, current_process_identity, dispatch_private_process_role,
};
use lazaret_state_anchor::{
FuseOverlayfsMount, ProtectedRuntimeFiles, StateAnchorAcquisition, StateAnchorLayout,
StateAnchorSandboxView, unmount_after_coordinator_loss,
FuseOverlayfsMount, ProtectedRuntimeFiles, RuntimeStateAnchorAuthority, StateAnchorAcquisition,
StateAnchorLaunchAuthority, StateAnchorLayout, StateAnchorSandboxView,
unmount_after_coordinator_loss,
};
use rustix::process::Signal;
@ -77,6 +78,45 @@ fn run() -> io::Result<()> {
};
let layout = StateAnchorLayout::create(&configuration).map_err(io::Error::other)?;
let launch =
StateAnchorLaunchAuthority::capture(&layout, &artifact).map_err(io::Error::other)?;
let runtime_authority = RuntimeStateAnchorAuthority::from_inherited(
launch.lower_fd(),
launch.persistent_anchor_fd(),
launch.runtime_anchor_fd(),
launch.expected_lower(),
)
.map_err(io::Error::other)?;
let expected = std::cell::Cell::new(None);
let runtime_mount = runtime_authority
.acquire(
current_process_identity()?,
ProcessOwnershipContext {
domain_id: DomainId::new([1; 32]),
generation_id: GenerationId::new(1),
coordinator_id: CoordinatorId::new([3; 32]),
slot: HostProcessOwnershipSlot::StateAnchorDaemon,
},
|staged| {
expected.set(Some(staged));
Ok(())
},
|staged| Ok(ProcessOwnershipCommitAck::v1(staged)),
|readiness| {
if expected.get() != Some(readiness.staged())
|| lazaret_linux::filesystem::current_mount_identity(layout.merged())?
!= readiness.mount()
{
return Err(io::Error::other(
"inherited State Anchor readiness changed authority",
));
}
Ok(())
},
)
.map_err(io::Error::other)?;
runtime_mount.unmount().map_err(io::Error::other)?;
let first = acquire(&layout, &artifact)?;
fs::write(
layout.merged().join("usr/bin/installed-tool"),