Enforce sandbox causal edge stdio policies
This commit is contained in:
parent
b653293840
commit
903ff837d6
1 changed files with 185 additions and 33 deletions
|
|
@ -3,7 +3,6 @@ use std::fs::File;
|
|||
use std::io;
|
||||
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
|
||||
use std::os::unix::fs::FileExt;
|
||||
use std::process::Stdio;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use lazaret_core::codec::{decode, encode};
|
||||
|
|
@ -13,8 +12,8 @@ use lazaret_core::records::{
|
|||
};
|
||||
use lazaret_linux::capability;
|
||||
use lazaret_linux::process::{
|
||||
ChildStandardIo, ProcessOwnershipContext, RetainedProcess, TargetCommand, child_broker,
|
||||
current_process_identity,
|
||||
ChildStandardIo, ParentEdge, ProcessOwnershipContext, RetainedProcess, TargetCommand,
|
||||
child_broker, current_process_identity,
|
||||
};
|
||||
use rustix::event::{PollFd, PollFlags, Timespec, poll};
|
||||
use rustix::fs::{MemfdFlags, memfd_create};
|
||||
|
|
@ -170,6 +169,24 @@ impl RuntimeSupervisorLaunch {
|
|||
pub const fn ownership(&self) -> ProcessOwnershipContext {
|
||||
self.ownership
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// Refuses a Runtime Supervisor target without the lifetime-pipe parent edge.
|
||||
pub fn child_standard_io(
|
||||
&self,
|
||||
private_control: OwnedFd,
|
||||
lifetime_pipe: OwnedFd,
|
||||
) -> io::Result<ChildStandardIo> {
|
||||
if self.target.parent_edge() != ParentEdge::LifetimePipe {
|
||||
return Err(io::Error::other(
|
||||
"Runtime Supervisor launch requires the lifetime-pipe parent edge",
|
||||
));
|
||||
}
|
||||
Ok(ChildStandardIo::private_control_with_lifetime_pipe(
|
||||
private_control,
|
||||
lifetime_pipe,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the Runtime Supervisor's private early role before ordinary binary dispatch.
|
||||
|
|
@ -273,7 +290,7 @@ fn run_supervisor(arguments: &RuntimeArguments) -> io::Result<()> {
|
|||
parent,
|
||||
arguments.ownership,
|
||||
&runsc,
|
||||
ChildStandardIo::redirected(Stdio::null(), Stdio::null()),
|
||||
attached_runsc_standard_io(&runsc)?,
|
||||
|ownership| {
|
||||
staged.set(Some(ownership));
|
||||
send_message(&control, &SupervisorEvent::Staged(ownership))
|
||||
|
|
@ -347,6 +364,15 @@ fn runsc_target(arguments: &RuntimeArguments, pid_file: i32) -> io::Result<Targe
|
|||
Ok(target.with_parent_death_kill_edge())
|
||||
}
|
||||
|
||||
fn attached_runsc_standard_io(target: &TargetCommand) -> io::Result<ChildStandardIo> {
|
||||
if target.parent_edge() != ParentEdge::ParentDeathKill {
|
||||
return Err(io::Error::other(
|
||||
"attached runsc requires the parent-death KILL edge",
|
||||
));
|
||||
}
|
||||
Ok(ChildStandardIo::silenced())
|
||||
}
|
||||
|
||||
fn wait_for_runsc_ready(pid_file: &File, process: &RetainedProcess) -> io::Result<u32> {
|
||||
let deadline = Instant::now() + READINESS_TIMEOUT;
|
||||
let mut bytes = [0_u8; 32];
|
||||
|
|
@ -559,6 +585,8 @@ mod tests {
|
|||
use lazaret_core::identity::{CoordinatorId, DomainId, GenerationId};
|
||||
use lazaret_core::records::HostProcessOwnershipSlot;
|
||||
use lazaret_linux::ipc::private_stream_pair;
|
||||
use lazaret_linux::process::ChildStandardIoPolicy;
|
||||
use rustix::pipe::{PipeFlags, pipe_with};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -573,6 +601,47 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_supervisor_and_runsc_keep_distinct_edge_and_stdio_policies() {
|
||||
let ownership = ProcessOwnershipContext {
|
||||
domain_id: DomainId::new([1; 32]),
|
||||
generation_id: GenerationId::new(7),
|
||||
coordinator_id: CoordinatorId::new([2; 32]),
|
||||
slot: HostProcessOwnershipSlot::SandboxRuntimeSupervisor,
|
||||
};
|
||||
let launch = RuntimeSupervisorLaunch {
|
||||
target: TargetCommand::new("/proc/self/exe").with_lifetime_pipe_parent_edge(),
|
||||
ownership,
|
||||
};
|
||||
let (_coordinator_control, supervisor_control) = private_stream_pair().unwrap();
|
||||
let (supervisor_lifetime, _coordinator_lifetime) = pipe_with(PipeFlags::CLOEXEC).unwrap();
|
||||
assert_eq!(launch.target().parent_edge(), ParentEdge::LifetimePipe);
|
||||
assert_eq!(
|
||||
launch
|
||||
.child_standard_io(supervisor_control, supervisor_lifetime)
|
||||
.unwrap()
|
||||
.policy(),
|
||||
ChildStandardIoPolicy::PrivateControlWithLifetimePipe
|
||||
);
|
||||
|
||||
let runsc_arguments = RuntimeArguments {
|
||||
ownership: ProcessOwnershipContext {
|
||||
slot: HostProcessOwnershipSlot::SandboxAttachedRunsc,
|
||||
..ownership
|
||||
},
|
||||
runsc_program: "runsc".into(),
|
||||
runsc_arguments: ["-root=/runtime", "run", "container"]
|
||||
.map(OsString::from)
|
||||
.into(),
|
||||
};
|
||||
let runsc = runsc_target(&runsc_arguments, 9).unwrap();
|
||||
assert_eq!(runsc.parent_edge(), ParentEdge::ParentDeathKill);
|
||||
assert_eq!(
|
||||
attached_runsc_standard_io(&runsc).unwrap().policy(),
|
||||
ChildStandardIoPolicy::Silenced
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_role_parser_preserves_exact_ownership_and_runsc_arguments() {
|
||||
let domain = [1_u8; 32];
|
||||
|
|
|
|||
Loading…
Reference in a new issue