Enforce sandbox causal edge stdio policies
This commit is contained in:
parent
b653293840
commit
903ff837d6
4 changed files with 185 additions and 33 deletions
|
|
@ -2,7 +2,6 @@ use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Stdio;
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use lazaret_core::identity::{
|
use lazaret_core::identity::{
|
||||||
|
|
@ -14,9 +13,7 @@ use lazaret_core::records::{
|
||||||
StagedProcessOwnership,
|
StagedProcessOwnership,
|
||||||
};
|
};
|
||||||
use lazaret_linux::ipc::private_stream_pair;
|
use lazaret_linux::ipc::private_stream_pair;
|
||||||
use lazaret_linux::process::{
|
use lazaret_linux::process::{RetainedProcess, child_broker, current_process_identity};
|
||||||
ChildStandardIo, RetainedProcess, child_broker, current_process_identity,
|
|
||||||
};
|
|
||||||
use lazaret_runtime_supervisor::supervision::{
|
use lazaret_runtime_supervisor::supervision::{
|
||||||
AttachedRunscSignal, CoordinatorChannel, RuntimeSupervisorLaunch, SupervisorEvent,
|
AttachedRunscSignal, CoordinatorChannel, RuntimeSupervisorLaunch, SupervisorEvent,
|
||||||
};
|
};
|
||||||
|
|
@ -373,10 +370,7 @@ impl AwaitingAttachedRunsc {
|
||||||
parent,
|
parent,
|
||||||
launch.ownership(),
|
launch.ownership(),
|
||||||
launch.target(),
|
launch.target(),
|
||||||
ChildStandardIo::redirected(
|
launch.child_standard_io(supervisor_control, supervisor_lifetime)?,
|
||||||
Stdio::from(supervisor_control),
|
|
||||||
Stdio::from(supervisor_lifetime),
|
|
||||||
),
|
|
||||||
|staged| {
|
|staged| {
|
||||||
coordinator
|
coordinator
|
||||||
.stage_runtime_supervisor(staged)
|
.stage_runtime_supervisor(staged)
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,12 @@ static CHILD_BROKER: OnceLock<ChildBroker> = OnceLock::new();
|
||||||
pub struct TargetCommand {
|
pub struct TargetCommand {
|
||||||
program: OsString,
|
program: OsString,
|
||||||
arguments: Vec<OsString>,
|
arguments: Vec<OsString>,
|
||||||
parent_action: ParentAction,
|
parent_edge: ParentEdge,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum ParentAction {
|
pub enum ParentEdge {
|
||||||
Kill,
|
ParentDeathKill,
|
||||||
LifetimePipe,
|
LifetimePipe,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ impl TargetCommand {
|
||||||
Self {
|
Self {
|
||||||
program: program.into(),
|
program: program.into(),
|
||||||
arguments: Vec::new(),
|
arguments: Vec::new(),
|
||||||
parent_action: ParentAction::Kill,
|
parent_edge: ParentEdge::ParentDeathKill,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,23 +56,28 @@ impl TargetCommand {
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_lifetime_pipe_parent_edge(mut self) -> Self {
|
pub fn with_lifetime_pipe_parent_edge(mut self) -> Self {
|
||||||
self.parent_action = ParentAction::LifetimePipe;
|
self.parent_edge = ParentEdge::LifetimePipe;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_parent_death_kill_edge(mut self) -> Self {
|
pub fn with_parent_death_kill_edge(mut self) -> Self {
|
||||||
self.parent_action = ParentAction::Kill;
|
self.parent_edge = ParentEdge::ParentDeathKill;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn parent_edge(&self) -> ParentEdge {
|
||||||
|
self.parent_edge
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::disallowed_types)]
|
#[allow(clippy::disallowed_types)]
|
||||||
fn append_to(&self, command: &mut std::process::Command) {
|
fn append_to(&self, command: &mut std::process::Command) {
|
||||||
command
|
command
|
||||||
.arg("--parent-action")
|
.arg("--parent-action")
|
||||||
.arg(match self.parent_action {
|
.arg(match self.parent_edge {
|
||||||
ParentAction::Kill => "kill",
|
ParentEdge::ParentDeathKill => "kill",
|
||||||
ParentAction::LifetimePipe => "lifetime-pipe",
|
ParentEdge::LifetimePipe => "lifetime-pipe",
|
||||||
})
|
})
|
||||||
.arg("--")
|
.arg("--")
|
||||||
.arg(&self.program)
|
.arg(&self.program)
|
||||||
|
|
@ -83,6 +88,14 @@ impl TargetCommand {
|
||||||
pub struct ChildStandardIo {
|
pub struct ChildStandardIo {
|
||||||
stdout: Option<Stdio>,
|
stdout: Option<Stdio>,
|
||||||
stderr: Option<Stdio>,
|
stderr: Option<Stdio>,
|
||||||
|
policy: ChildStandardIoPolicy,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ChildStandardIoPolicy {
|
||||||
|
Inherit,
|
||||||
|
PrivateControlWithLifetimePipe,
|
||||||
|
Silenced,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChildStandardIo {
|
impl ChildStandardIo {
|
||||||
|
|
@ -91,16 +104,35 @@ impl ChildStandardIo {
|
||||||
Self {
|
Self {
|
||||||
stdout: None,
|
stdout: None,
|
||||||
stderr: None,
|
stderr: None,
|
||||||
|
policy: ChildStandardIoPolicy::Inherit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn redirected(stdout: impl Into<Stdio>, stderr: impl Into<Stdio>) -> Self {
|
pub fn private_control_with_lifetime_pipe(
|
||||||
|
control: impl Into<Stdio>,
|
||||||
|
lifetime_pipe: impl Into<Stdio>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stdout: Some(stdout.into()),
|
stdout: Some(control.into()),
|
||||||
stderr: Some(stderr.into()),
|
stderr: Some(lifetime_pipe.into()),
|
||||||
|
policy: ChildStandardIoPolicy::PrivateControlWithLifetimePipe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn silenced() -> Self {
|
||||||
|
Self {
|
||||||
|
stdout: Some(Stdio::null()),
|
||||||
|
stderr: Some(Stdio::null()),
|
||||||
|
policy: ChildStandardIoPolicy::Silenced,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn policy(&self) -> ChildStandardIoPolicy {
|
||||||
|
self.policy
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
|
@ -159,6 +191,27 @@ pub fn child_broker() -> &'static ChildBroker {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn require_parent_edge_standard_io(
|
||||||
|
parent_edge: ParentEdge,
|
||||||
|
standard_io: ChildStandardIoPolicy,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match (parent_edge, standard_io) {
|
||||||
|
(ParentEdge::LifetimePipe, ChildStandardIoPolicy::PrivateControlWithLifetimePipe)
|
||||||
|
| (
|
||||||
|
ParentEdge::ParentDeathKill,
|
||||||
|
ChildStandardIoPolicy::Inherit | ChildStandardIoPolicy::Silenced,
|
||||||
|
) => Ok(()),
|
||||||
|
(ParentEdge::LifetimePipe, _) => Err(io::Error::other(
|
||||||
|
"lifetime-pipe parent edge requires private control stdout and lifetime-pipe stderr",
|
||||||
|
)),
|
||||||
|
(ParentEdge::ParentDeathKill, ChildStandardIoPolicy::PrivateControlWithLifetimePipe) => {
|
||||||
|
Err(io::Error::other(
|
||||||
|
"parent-death edge cannot substitute a lifetime-pipe stdio policy",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ChildBroker {
|
impl ChildBroker {
|
||||||
/// Spawns the repository wrapper, stages exact ownership, accepts its acknowledgment,
|
/// Spawns the repository wrapper, stages exact ownership, accepts its acknowledgment,
|
||||||
/// and only then releases target execution.
|
/// and only then releases target execution.
|
||||||
|
|
@ -208,6 +261,7 @@ impl ChildBroker {
|
||||||
.exclusion
|
.exclusion
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|_| io::Error::other("child broker lock poisoned"))?;
|
.map_err(|_| io::Error::other("child broker lock poisoned"))?;
|
||||||
|
require_parent_edge_standard_io(target.parent_edge(), standard_io.policy())?;
|
||||||
require_default_sigchld()?;
|
require_default_sigchld()?;
|
||||||
require_reapable_sigchld()?;
|
require_reapable_sigchld()?;
|
||||||
let (release, wait) = launch_barrier()?;
|
let (release, wait) = launch_barrier()?;
|
||||||
|
|
@ -306,11 +360,11 @@ fn run_wrapper_role(arguments: Vec<OsString>) -> io::Result<()> {
|
||||||
let (expected_parent, target) = parse_wrapper_arguments(arguments)?;
|
let (expected_parent, target) = parse_wrapper_arguments(arguments)?;
|
||||||
BarrierWait::from_stdin()?.wait()?;
|
BarrierWait::from_stdin()?.wait()?;
|
||||||
rustix::io::fcntl_setfd(std::io::stdin(), rustix::io::FdFlags::CLOEXEC)?;
|
rustix::io::fcntl_setfd(std::io::stdin(), rustix::io::FdFlags::CLOEXEC)?;
|
||||||
match target.parent_action {
|
match target.parent_edge {
|
||||||
ParentAction::Kill => {
|
ParentEdge::ParentDeathKill => {
|
||||||
arm_parent_death_and_recheck(Signal::KILL, expected_parent)?;
|
arm_parent_death_and_recheck(Signal::KILL, expected_parent)?;
|
||||||
}
|
}
|
||||||
ParentAction::LifetimePipe => {
|
ParentEdge::LifetimePipe => {
|
||||||
require_lifetime_pipe_and_recheck(expected_parent)?;
|
require_lifetime_pipe_and_recheck(expected_parent)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -779,9 +833,9 @@ pub fn parse_wrapper_arguments(
|
||||||
let inode = number_argument(&mut arguments, "--parent-inode")?;
|
let inode = number_argument(&mut arguments, "--parent-inode")?;
|
||||||
let pid = number_argument(&mut arguments, "--parent-pid")?;
|
let pid = number_argument(&mut arguments, "--parent-pid")?;
|
||||||
let start = number_argument(&mut arguments, "--parent-start")?;
|
let start = number_argument(&mut arguments, "--parent-start")?;
|
||||||
let parent_action = match named_argument(&mut arguments, "--parent-action")?.to_str() {
|
let parent_edge = match named_argument(&mut arguments, "--parent-action")?.to_str() {
|
||||||
Some("kill") => ParentAction::Kill,
|
Some("kill") => ParentEdge::ParentDeathKill,
|
||||||
Some("lifetime-pipe") => ParentAction::LifetimePipe,
|
Some("lifetime-pipe") => ParentEdge::LifetimePipe,
|
||||||
_ => return Err(io::Error::other("wrapper parent action is invalid")),
|
_ => return Err(io::Error::other("wrapper parent action is invalid")),
|
||||||
};
|
};
|
||||||
if arguments.next().as_deref() != Some(OsStr::new("--")) {
|
if arguments.next().as_deref() != Some(OsStr::new("--")) {
|
||||||
|
|
@ -793,7 +847,7 @@ pub fn parse_wrapper_arguments(
|
||||||
let target = TargetCommand {
|
let target = TargetCommand {
|
||||||
program,
|
program,
|
||||||
arguments: arguments.collect(),
|
arguments: arguments.collect(),
|
||||||
parent_action,
|
parent_edge,
|
||||||
};
|
};
|
||||||
let boot = parse_boot_hex(&boot)?;
|
let boot = parse_boot_hex(&boot)?;
|
||||||
Ok((
|
Ok((
|
||||||
|
|
@ -880,6 +934,38 @@ mod tests {
|
||||||
assert!(std::ptr::eq(child_broker(), child_broker()));
|
assert!(std::ptr::eq(child_broker(), child_broker()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parent_edges_require_their_exact_stdio_policy() {
|
||||||
|
assert!(
|
||||||
|
require_parent_edge_standard_io(
|
||||||
|
ParentEdge::LifetimePipe,
|
||||||
|
ChildStandardIoPolicy::PrivateControlWithLifetimePipe,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
require_parent_edge_standard_io(
|
||||||
|
ParentEdge::LifetimePipe,
|
||||||
|
ChildStandardIoPolicy::Silenced,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
require_parent_edge_standard_io(
|
||||||
|
ParentEdge::ParentDeathKill,
|
||||||
|
ChildStandardIoPolicy::Silenced,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
require_parent_edge_standard_io(
|
||||||
|
ParentEdge::ParentDeathKill,
|
||||||
|
ChildStandardIoPolicy::PrivateControlWithLifetimePipe,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn barrier_reader_is_inheritable_and_writer_is_close_on_exec() {
|
fn barrier_reader_is_inheritable_and_writer_is_close_on_exec() {
|
||||||
let (release, wait) = launch_barrier().unwrap();
|
let (release, wait) = launch_barrier().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,10 @@ fn lifetime_pipe_descriptor_contract() -> std::io::Result<()> {
|
||||||
parent,
|
parent,
|
||||||
context(),
|
context(),
|
||||||
&target,
|
&target,
|
||||||
ChildStandardIo::redirected(Stdio::null(), Stdio::from(lifetime_reader)),
|
ChildStandardIo::private_control_with_lifetime_pipe(
|
||||||
|
Stdio::null(),
|
||||||
|
Stdio::from(lifetime_reader),
|
||||||
|
),
|
||||||
|_| Ok(()),
|
|_| Ok(()),
|
||||||
|staged| Ok(ProcessOwnershipCommitAck::v1(staged)),
|
|staged| Ok(ProcessOwnershipCommitAck::v1(staged)),
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -108,7 +111,7 @@ fn run_lifetime_pipe_target(marker: &std::path::Path, stderr: Stdio) -> std::io:
|
||||||
parent,
|
parent,
|
||||||
context(),
|
context(),
|
||||||
&target,
|
&target,
|
||||||
ChildStandardIo::redirected(Stdio::null(), stderr),
|
ChildStandardIo::private_control_with_lifetime_pipe(Stdio::null(), stderr),
|
||||||
|_| Ok(()),
|
|_| Ok(()),
|
||||||
|staged| Ok(ProcessOwnershipCommitAck::v1(staged)),
|
|staged| Ok(ProcessOwnershipCommitAck::v1(staged)),
|
||||||
)?;
|
)?;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
|
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
|
||||||
use std::os::unix::fs::FileExt;
|
use std::os::unix::fs::FileExt;
|
||||||
use std::process::Stdio;
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use lazaret_core::codec::{decode, encode};
|
use lazaret_core::codec::{decode, encode};
|
||||||
|
|
@ -13,8 +12,8 @@ use lazaret_core::records::{
|
||||||
};
|
};
|
||||||
use lazaret_linux::capability;
|
use lazaret_linux::capability;
|
||||||
use lazaret_linux::process::{
|
use lazaret_linux::process::{
|
||||||
ChildStandardIo, ProcessOwnershipContext, RetainedProcess, TargetCommand, child_broker,
|
ChildStandardIo, ParentEdge, ProcessOwnershipContext, RetainedProcess, TargetCommand,
|
||||||
current_process_identity,
|
child_broker, current_process_identity,
|
||||||
};
|
};
|
||||||
use rustix::event::{PollFd, PollFlags, Timespec, poll};
|
use rustix::event::{PollFd, PollFlags, Timespec, poll};
|
||||||
use rustix::fs::{MemfdFlags, memfd_create};
|
use rustix::fs::{MemfdFlags, memfd_create};
|
||||||
|
|
@ -170,6 +169,24 @@ impl RuntimeSupervisorLaunch {
|
||||||
pub const fn ownership(&self) -> ProcessOwnershipContext {
|
pub const fn ownership(&self) -> ProcessOwnershipContext {
|
||||||
self.ownership
|
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.
|
/// Runs the Runtime Supervisor's private early role before ordinary binary dispatch.
|
||||||
|
|
@ -273,7 +290,7 @@ fn run_supervisor(arguments: &RuntimeArguments) -> io::Result<()> {
|
||||||
parent,
|
parent,
|
||||||
arguments.ownership,
|
arguments.ownership,
|
||||||
&runsc,
|
&runsc,
|
||||||
ChildStandardIo::redirected(Stdio::null(), Stdio::null()),
|
attached_runsc_standard_io(&runsc)?,
|
||||||
|ownership| {
|
|ownership| {
|
||||||
staged.set(Some(ownership));
|
staged.set(Some(ownership));
|
||||||
send_message(&control, &SupervisorEvent::Staged(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())
|
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> {
|
fn wait_for_runsc_ready(pid_file: &File, process: &RetainedProcess) -> io::Result<u32> {
|
||||||
let deadline = Instant::now() + READINESS_TIMEOUT;
|
let deadline = Instant::now() + READINESS_TIMEOUT;
|
||||||
let mut bytes = [0_u8; 32];
|
let mut bytes = [0_u8; 32];
|
||||||
|
|
@ -559,6 +585,8 @@ mod tests {
|
||||||
use lazaret_core::identity::{CoordinatorId, DomainId, GenerationId};
|
use lazaret_core::identity::{CoordinatorId, DomainId, GenerationId};
|
||||||
use lazaret_core::records::HostProcessOwnershipSlot;
|
use lazaret_core::records::HostProcessOwnershipSlot;
|
||||||
use lazaret_linux::ipc::private_stream_pair;
|
use lazaret_linux::ipc::private_stream_pair;
|
||||||
|
use lazaret_linux::process::ChildStandardIoPolicy;
|
||||||
|
use rustix::pipe::{PipeFlags, pipe_with};
|
||||||
|
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn runtime_role_parser_preserves_exact_ownership_and_runsc_arguments() {
|
fn runtime_role_parser_preserves_exact_ownership_and_runsc_arguments() {
|
||||||
let domain = [1_u8; 32];
|
let domain = [1_u8; 32];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue