Own the patched runsc artifact and bind recovery identity
This commit is contained in:
parent
c474fa4a23
commit
2c420012bd
8 changed files with 1967 additions and 130 deletions
|
|
@ -89,6 +89,8 @@ digest_identity!(
|
|||
DerivedPolicyDigest,
|
||||
ReadinessFingerprint,
|
||||
BundleDigest,
|
||||
RunscBuildId,
|
||||
RunscDigest,
|
||||
SelectedManifestDigest,
|
||||
IdMapDigest,
|
||||
CertificateDigest,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ use crate::identity::{
|
|||
GuestProcessGroupId, GuestProcessId, GuestProcessStartTimeTicks, HostPath, IdMapDigest,
|
||||
InodeId, MountIdentity, NamespaceIdentity, NetworkSidecarId, PidfsProcessAuthorityV1,
|
||||
PidfsProcessIdentityV1, PolicyId, PrepareOperationId, PreparedArtifactId, ProtocolCredentialId,
|
||||
ReadinessFingerprint, RequestDigest, RequestId, SandboxId, SelectedManifestDigest,
|
||||
SessionAnchorId, SessionId, SourceIdentity, StreamDigest, TrustManifestDigest,
|
||||
ReadinessFingerprint, RequestDigest, RequestId, RunscBuildId, RunscDigest, SandboxId,
|
||||
SelectedManifestDigest, SessionAnchorId, SessionId, SourceIdentity, StreamDigest,
|
||||
TrustManifestDigest,
|
||||
};
|
||||
|
||||
mod configuration;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use super::{
|
|||
DeviceId, DomainId, FileDescriptor, GenerationId, GuestProcessGroupId, GuestProcessId,
|
||||
GuestProcessStartTimeTicks, HostPath, InodeId, MountIdentity, NamespaceIdentity,
|
||||
NetworkReadinessEvidence, NetworkSidecarId, PidfsProcessIdentityV1, PreparedArtifactId,
|
||||
ReadinessFingerprint, RecordInvariantError, RecordTransitionError, RequestId,
|
||||
STORAGE_CATALOG_SCHEMA_ID, STORAGE_CATALOG_SCHEMA_VERSION, SandboxId, Serialize,
|
||||
ReadinessFingerprint, RecordInvariantError, RecordTransitionError, RequestId, RunscBuildId,
|
||||
RunscDigest, STORAGE_CATALOG_SCHEMA_ID, STORAGE_CATALOG_SCHEMA_VERSION, SandboxId, Serialize,
|
||||
SessionAnchorId, SessionId, SourceIdentity, fmt,
|
||||
};
|
||||
|
||||
|
|
@ -212,6 +212,18 @@ pub enum PersistedHostProcessOwnership {
|
|||
Unassigned,
|
||||
Staged(PidfsProcessIdentityV1),
|
||||
Committed(HostProcessIdentity),
|
||||
Runsc {
|
||||
build_id: RunscBuildId,
|
||||
digest: RunscDigest,
|
||||
process: RunscProcessOwnership,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum RunscProcessOwnership {
|
||||
Unassigned,
|
||||
Staged(PidfsProcessIdentityV1),
|
||||
Committed(HostProcessIdentity),
|
||||
}
|
||||
|
||||
impl PersistedHostProcessOwnership {
|
||||
|
|
@ -230,23 +242,103 @@ impl PersistedHostProcessOwnership {
|
|||
Self::Committed(HostProcessIdentity::pidfs_v1(identity))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn runsc_unassigned(build_id: RunscBuildId, digest: RunscDigest) -> Self {
|
||||
Self::Runsc {
|
||||
build_id,
|
||||
digest,
|
||||
process: RunscProcessOwnership::Unassigned,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn stage_runsc(&self, identity: PidfsProcessIdentityV1) -> Option<Self> {
|
||||
match self {
|
||||
Self::Runsc {
|
||||
build_id,
|
||||
digest,
|
||||
process: RunscProcessOwnership::Unassigned,
|
||||
} => Some(Self::Runsc {
|
||||
build_id: *build_id,
|
||||
digest: *digest,
|
||||
process: RunscProcessOwnership::Staged(identity),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn commit_runsc(&self, identity: PidfsProcessIdentityV1) -> Option<Self> {
|
||||
match self {
|
||||
Self::Runsc {
|
||||
build_id,
|
||||
digest,
|
||||
process: RunscProcessOwnership::Staged(_),
|
||||
} => Some(Self::Runsc {
|
||||
build_id: *build_id,
|
||||
digest: *digest,
|
||||
process: RunscProcessOwnership::Committed(HostProcessIdentity::pidfs_v1(identity)),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn runsc_identity(&self) -> Option<(RunscBuildId, RunscDigest)> {
|
||||
match self {
|
||||
Self::Runsc {
|
||||
build_id, digest, ..
|
||||
} => Some((*build_id, *digest)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_staged(&self) -> bool {
|
||||
matches!(self, Self::Staged(_))
|
||||
matches!(
|
||||
self,
|
||||
Self::Staged(_)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Staged(_),
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_unassigned(&self) -> bool {
|
||||
matches!(self, Self::Unassigned)
|
||||
matches!(
|
||||
self,
|
||||
Self::Unassigned
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Unassigned,
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_current_committed(&self) -> bool {
|
||||
matches!(self, Self::Committed(_))
|
||||
matches!(
|
||||
self,
|
||||
Self::Committed(_)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Committed(_),
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const fn is_initial_acquisition(&self) -> bool {
|
||||
matches!(self, Self::Unassigned | Self::Staged(_))
|
||||
matches!(
|
||||
self,
|
||||
Self::Unassigned
|
||||
| Self::Staged(_)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Unassigned | RunscProcessOwnership::Staged(_),
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const fn is_initial_or_current_committed(&self) -> bool {
|
||||
|
|
@ -257,9 +349,21 @@ impl PersistedHostProcessOwnership {
|
|||
/// Unassigned ownership has no positive authority.
|
||||
pub fn authoritative_pidfs(&self) -> Result<&PidfsProcessIdentityV1, ProcessAuthorityRefusal> {
|
||||
match self {
|
||||
Self::Unassigned => Err(ProcessAuthorityRefusal::Unassigned),
|
||||
Self::Staged(identity) => Ok(identity),
|
||||
Self::Committed(identity) => Ok(identity.pidfs()),
|
||||
Self::Unassigned
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Unassigned,
|
||||
..
|
||||
} => Err(ProcessAuthorityRefusal::Unassigned),
|
||||
Self::Staged(identity)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Staged(identity),
|
||||
..
|
||||
} => Ok(identity),
|
||||
Self::Committed(identity)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Committed(identity),
|
||||
..
|
||||
} => Ok(identity.pidfs()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,9 +371,21 @@ impl PersistedHostProcessOwnership {
|
|||
/// Unassigned or staged ownership is not serviceable.
|
||||
pub fn serviceable_pidfs(&self) -> Result<&PidfsProcessIdentityV1, ProcessOwnershipRefusal> {
|
||||
match self {
|
||||
Self::Unassigned => Err(ProcessOwnershipRefusal::Unassigned),
|
||||
Self::Staged(_) => Err(ProcessOwnershipRefusal::Staged),
|
||||
Self::Committed(identity) => Ok(identity.pidfs()),
|
||||
Self::Unassigned
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Unassigned,
|
||||
..
|
||||
} => Err(ProcessOwnershipRefusal::Unassigned),
|
||||
Self::Staged(_)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Staged(_),
|
||||
..
|
||||
} => Err(ProcessOwnershipRefusal::Staged),
|
||||
Self::Committed(identity)
|
||||
| Self::Runsc {
|
||||
process: RunscProcessOwnership::Committed(identity),
|
||||
..
|
||||
} => Ok(identity.pidfs()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -640,6 +640,24 @@ pub(super) fn validate_process_progress(
|
|||
old: &PersistedHostProcessOwnership,
|
||||
next: &PersistedHostProcessOwnership,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
if let (
|
||||
PersistedHostProcessOwnership::Runsc {
|
||||
build_id: old_build,
|
||||
digest: old_digest,
|
||||
process: old_process,
|
||||
},
|
||||
PersistedHostProcessOwnership::Runsc {
|
||||
build_id: next_build,
|
||||
digest: next_digest,
|
||||
process: next_process,
|
||||
},
|
||||
) = (old, next)
|
||||
{
|
||||
if old_build != next_build || old_digest != next_digest {
|
||||
return Err(RecordTransitionError::EvidenceChanged);
|
||||
}
|
||||
return validate_runsc_process_progress(old_process, next_process);
|
||||
}
|
||||
match (old, next) {
|
||||
(
|
||||
PersistedHostProcessOwnership::Unassigned,
|
||||
|
|
@ -672,6 +690,24 @@ pub(super) fn validate_process_progress(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_runsc_process_progress(
|
||||
old: &super::RunscProcessOwnership,
|
||||
next: &super::RunscProcessOwnership,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
use super::RunscProcessOwnership::{Committed, Staged, Unassigned};
|
||||
match (old, next) {
|
||||
(Unassigned, Unassigned | Staged(_)) => Ok(()),
|
||||
(Unassigned, Committed(_)) => Err(RecordTransitionError::ProcessStageSkipped),
|
||||
(Staged(_) | Committed(_), Unassigned) | (Committed(_), Staged(_)) => {
|
||||
Err(RecordTransitionError::EvidenceLost)
|
||||
}
|
||||
(Staged(old), Staged(next)) if old == next => Ok(()),
|
||||
(Staged(old), Committed(next)) if old == next.pidfs() => Ok(()),
|
||||
(Committed(old), Committed(next)) if old == next => Ok(()),
|
||||
_ => Err(RecordTransitionError::EvidenceChanged),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn validate_existing_process_progress(
|
||||
old: &PersistedHostProcessOwnership,
|
||||
next: &PersistedHostProcessOwnership,
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ use super::{
|
|||
PreparedLowerOwnership, ProcessOwnershipCommitAck, ProcessOwnershipMessageVersion,
|
||||
ProtocolCredential, ProtocolCredentialRole, ProtocolPublicationIdentity, PtyIdentity,
|
||||
PublicationOwnership, ResolvedAutoApprovalRule, ResolvedVolume, Resolver, ResultStream,
|
||||
SandboxCredentialBundle, SandboxOwnership, Session, SessionBinding, SessionClose, SessionExit,
|
||||
SessionExitOutcome, SessionRegistrationRequest, SessionRegistrationResponse,
|
||||
SessionRequestCapability, SessionTerminal, SessionTerminalEvent, SessionTerminalMessage,
|
||||
SessionTerminalState, SignedProtocolRecord, StagedProcessOwnership, StateAnchorOwnership,
|
||||
StateAnchorReleaseEvidence, StorageCatalog, StorageCatalogMetadata, StoreMetadata,
|
||||
TerminalInput, TerminalOutput, TerminalPrompt, TerminalResize, TerminalSignal,
|
||||
RunscProcessOwnership, SandboxCredentialBundle, SandboxOwnership, Session, SessionBinding,
|
||||
SessionClose, SessionExit, SessionExitOutcome, SessionRegistrationRequest,
|
||||
SessionRegistrationResponse, SessionRequestCapability, SessionTerminal, SessionTerminalEvent,
|
||||
SessionTerminalMessage, SessionTerminalState, SignedProtocolRecord, StagedProcessOwnership,
|
||||
StateAnchorOwnership, StateAnchorReleaseEvidence, StorageCatalog, StorageCatalogMetadata,
|
||||
StoreMetadata, TerminalInput, TerminalOutput, TerminalPrompt, TerminalResize, TerminalSignal,
|
||||
TerminalSignalKind, TlsCredential, TlsRole, TrustManifest, TrustedHostConfigurationV1,
|
||||
};
|
||||
use crate::protocol::{BootstrapWaitOutcome, BootstrapWaitRequest};
|
||||
|
|
@ -60,6 +60,7 @@ schema_types!(
|
|||
"PidfsProcessIdentityV1" => PidfsProcessIdentityV1,
|
||||
"HostProcessIdentity" => HostProcessIdentity,
|
||||
"PersistedHostProcessOwnership" => PersistedHostProcessOwnership,
|
||||
"RunscProcessOwnership" => RunscProcessOwnership,
|
||||
"HostProcessOwnershipSlot" => HostProcessOwnershipSlot,
|
||||
"ProcessOwnershipMessageVersion" => ProcessOwnershipMessageVersion,
|
||||
"StagedProcessOwnership" => StagedProcessOwnership,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ use lazaret_core::identity::{
|
|||
HostPidLocator, IdMapDigest, InodeId, MountId, MountIdentity, NamespaceIdentity,
|
||||
NetworkSidecarId, PidfsDeviceId, PidfsInodeId, PidfsProcessAuthorityV1, PidfsProcessIdentityV1,
|
||||
PolicyId, PrepareOperationId, PreparedArtifactId, ProcessStartTimeTicks, ProtocolCredentialId,
|
||||
ReadinessFingerprint, RequestDigest, RequestId, SandboxId, SelectedManifestDigest,
|
||||
SessionAnchorId, SessionId, SourceIdentity, StreamDigest, TrustManifestDigest,
|
||||
ReadinessFingerprint, RequestDigest, RequestId, RunscBuildId, RunscDigest, SandboxId,
|
||||
SelectedManifestDigest, SessionAnchorId, SessionId, SourceIdentity, StreamDigest,
|
||||
TrustManifestDigest,
|
||||
};
|
||||
use lazaret_core::network::readiness_fingerprint as derive_readiness_fingerprint;
|
||||
use lazaret_core::protocol::{BootstrapWaitOutcome, BootstrapWaitRequest};
|
||||
|
|
@ -27,6 +28,33 @@ struct SchemaCorpus {
|
|||
digest: Sha256,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sandbox_ownership_decodes_records_without_runsc_identity() {
|
||||
#[derive(Serialize)]
|
||||
struct LegacySandboxOwnership {
|
||||
container_id: Option<ContainerId>,
|
||||
runtime_root: Option<HostPath>,
|
||||
runtime_root_identity: Option<MountIdentity>,
|
||||
bundle_digest: Option<BundleDigest>,
|
||||
host_coordinator: PersistedHostProcessOwnership,
|
||||
runtime_supervisor: PersistedHostProcessOwnership,
|
||||
attached_runsc: PersistedHostProcessOwnership,
|
||||
}
|
||||
|
||||
let encoded = postcard::to_stdvec(&LegacySandboxOwnership {
|
||||
container_id: None,
|
||||
runtime_root: None,
|
||||
runtime_root_identity: None,
|
||||
bundle_digest: None,
|
||||
host_coordinator: PersistedHostProcessOwnership::unassigned(),
|
||||
runtime_supervisor: PersistedHostProcessOwnership::unassigned(),
|
||||
attached_runsc: PersistedHostProcessOwnership::unassigned(),
|
||||
})
|
||||
.unwrap();
|
||||
let decoded = postcard::from_bytes::<SandboxOwnership>(&encoded).unwrap();
|
||||
assert!(decoded.attached_runsc.is_unassigned());
|
||||
}
|
||||
|
||||
impl SchemaCorpus {
|
||||
fn insert(&mut self, name: &'static str, encoded: &[u8]) -> bool {
|
||||
self.digest.update(name.len().to_be_bytes());
|
||||
|
|
@ -529,7 +557,13 @@ fn complete_ownership(role: ParticipantRole, state: ParticipantState) -> Partici
|
|||
bundle_digest: Some(BundleDigest::new(opaque(43))),
|
||||
host_coordinator: owned_process(30),
|
||||
runtime_supervisor: owned_process(21),
|
||||
attached_runsc: owned_process(44),
|
||||
attached_runsc: PersistedHostProcessOwnership::Runsc {
|
||||
build_id: RunscBuildId::new(opaque(44)),
|
||||
digest: RunscDigest::new(opaque(45)),
|
||||
process: RunscProcessOwnership::Committed(HostProcessIdentity::pidfs_v1(process(
|
||||
44,
|
||||
))),
|
||||
},
|
||||
}),
|
||||
ParticipantRole::Publication => ParticipantOwnership::Publication(PublicationOwnership {
|
||||
staged_socket_path: Some(HostPath::new(b"staged-socket".to_vec())),
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ fn every_schema_shape_round_trips_and_rejects_malformed_or_unknown_versions() {
|
|||
PersistedHostProcessOwnership::staged(pidfs_identity),
|
||||
&mut seen,
|
||||
);
|
||||
verify_shape(RunscProcessOwnership::Staged(pidfs_identity), &mut seen);
|
||||
verify_shape(
|
||||
HostProcessOwnershipSlot::SessionTerminalExecClient(session_id()),
|
||||
&mut seen,
|
||||
|
|
@ -425,7 +426,13 @@ fn every_schema_shape_round_trips_and_rejects_malformed_or_unknown_versions() {
|
|||
bundle_digest: Some(BundleDigest::new(opaque(66))),
|
||||
host_coordinator: owned_process(30),
|
||||
runtime_supervisor: owned_process(21),
|
||||
attached_runsc: owned_process(67),
|
||||
attached_runsc: PersistedHostProcessOwnership::Runsc {
|
||||
build_id: RunscBuildId::new(opaque(67)),
|
||||
digest: RunscDigest::new(opaque(71)),
|
||||
process: RunscProcessOwnership::Committed(HostProcessIdentity::pidfs_v1(process(
|
||||
67,
|
||||
))),
|
||||
},
|
||||
},
|
||||
&mut seen,
|
||||
);
|
||||
|
|
@ -642,8 +649,8 @@ persistent_dirs = []
|
|||
assert_eq!(
|
||||
seen.digest(),
|
||||
[
|
||||
23, 80, 80, 177, 148, 141, 234, 213, 240, 108, 167, 148, 252, 121, 212, 128, 5, 195,
|
||||
176, 126, 71, 76, 141, 196, 174, 125, 212, 31, 115, 155, 178, 139,
|
||||
54, 187, 13, 149, 227, 157, 1, 54, 234, 66, 127, 9, 34, 65, 173, 20, 214, 200, 126, 67,
|
||||
1, 216, 152, 76, 167, 32, 177, 218, 0, 192, 175, 28,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,17 @@ fn lifecycle_corpus(digest: &mut Sha256) {
|
|||
PersistedHostProcessOwnership::Unassigned => PersistedHostProcessOwnership::unassigned(),
|
||||
PersistedHostProcessOwnership::Staged(_) => PersistedHostProcessOwnership::staged(process(1)),
|
||||
PersistedHostProcessOwnership::Committed(_) => PersistedHostProcessOwnership::committed(process(2)),
|
||||
PersistedHostProcessOwnership::Runsc { .. } => PersistedHostProcessOwnership::runsc_unassigned(
|
||||
RunscBuildId::new(opaque(3)),
|
||||
RunscDigest::new(opaque(4)),
|
||||
),
|
||||
});
|
||||
enum_corpus!(digest, RunscProcessOwnership, {
|
||||
RunscProcessOwnership::Unassigned => RunscProcessOwnership::Unassigned,
|
||||
RunscProcessOwnership::Staged(_) => RunscProcessOwnership::Staged(process(5)),
|
||||
RunscProcessOwnership::Committed(_) => RunscProcessOwnership::Committed(
|
||||
HostProcessIdentity::pidfs_v1(process(6)),
|
||||
),
|
||||
});
|
||||
enum_corpus!(digest, ProcessOwnershipMessageVersion, {
|
||||
ProcessOwnershipMessageVersion::V1 => ProcessOwnershipMessageVersion::V1,
|
||||
|
|
@ -314,8 +325,8 @@ fn every_serialized_enum_variant_has_fixed_shape_evidence() {
|
|||
assert_eq!(
|
||||
digest.finalize().as_slice(),
|
||||
[
|
||||
199, 150, 218, 48, 172, 14, 153, 234, 245, 198, 178, 249, 47, 35, 217, 83, 28, 188,
|
||||
123, 152, 3, 15, 150, 61, 79, 255, 244, 107, 132, 27, 167, 123,
|
||||
63, 126, 242, 211, 164, 165, 11, 185, 180, 135, 109, 135, 92, 142, 111, 169, 142, 215,
|
||||
49, 4, 170, 169, 119, 237, 235, 161, 192, 89, 92, 93, 88, 35,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue