use std::process::{Command, Output};
use crate::orchestration::{CapabilityPolicy, SandboxProfile};
use crate::value::VmError;
use super::{
apply_process_config, build_std_command, process_spawn_error, spawn_error,
ProcessCommandConfig, SandboxMechanism, SandboxMechanismAvailability,
};
#[path = "conformance.rs"]
pub mod conformance;
#[path = "self_confinement.rs"]
pub mod self_confinement;
pub(crate) trait SandboxBackend {
fn name() -> &'static str;
fn filesystem_mechanism() -> SandboxMechanism;
fn filesystem_available() -> bool {
Self::available()
}
fn available() -> bool;
fn confine_current_process(policy: &CapabilityPolicy) -> Result<SandboxMechanism, VmError> {
Err(super::sandbox_rejection(format!(
"the {} sandbox backend cannot confine a running process; requested under the `{}` \
profile",
Self::name(),
policy.sandbox_profile.as_str()
)))
}
fn prepare_std_command(
program: &str,
args: &[String],
command: &mut Command,
policy: &CapabilityPolicy,
profile: SandboxProfile,
) -> Result<PrepareOutcome, VmError>;
fn prepare_tokio_command(
program: &str,
args: &[String],
command: &mut tokio::process::Command,
policy: &CapabilityPolicy,
profile: SandboxProfile,
) -> Result<PrepareOutcome, VmError>;
fn run_to_output(
program: &str,
args: &[String],
config: &ProcessCommandConfig,
policy: &CapabilityPolicy,
profile: SandboxProfile,
) -> Result<Output, VmError> {
let mut command = build_std_command::<Self>(program, args, policy, profile)?;
apply_process_config(&mut command, config, Some(policy));
super::launch_environment::validate_for_policy(
&mut command,
config.closed_env,
Some(policy),
)?;
crate::op_interrupt::capture_output_interruptible(&mut command)
.map_err(|error| process_spawn_error(&error).unwrap_or_else(|| spawn_error(error)))
}
#[cfg(unix)]
fn run_to_output_in_session(
program: &str,
args: &[String],
config: &ProcessCommandConfig,
policy: &CapabilityPolicy,
profile: SandboxProfile,
) -> Result<(Output, u32), VmError> {
let mut command = build_std_command::<Self>(program, args, policy, profile)?;
apply_process_config(&mut command, config, Some(policy));
super::launch_environment::validate_for_policy(
&mut command,
config.closed_env,
Some(policy),
)?;
crate::op_interrupt::capture_output_interruptible_in_session(&mut command)
.map_err(|error| process_spawn_error(&error).unwrap_or_else(|| spawn_error(error)))
}
}
pub(crate) enum PrepareOutcome {
Direct,
#[cfg(target_os = "linux")]
BubblewrapExec {
wrapper: String,
args: Vec<String>,
descriptors: super::linux::DescriptorTransfer,
},
#[cfg_attr(not(target_os = "macos"), allow(dead_code))]
WrappedExec {
wrapper: String,
args: Vec<String>,
},
#[cfg(target_os = "linux")]
NamespacedExec {
wrapper: String,
args: Vec<String>,
confinement: super::linux::TransferableConfinement,
},
}
#[cfg(target_os = "linux")]
pub(super) type ActiveBackend = super::linux::Backend;
#[cfg(target_os = "macos")]
pub(super) type ActiveBackend = super::macos::Backend;
#[cfg(target_os = "openbsd")]
pub(super) type ActiveBackend = super::openbsd::Backend;
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "openbsd")))]
pub(super) type ActiveBackend = UnconfinedBackend;
#[cfg_attr(
any(target_os = "linux", target_os = "macos", target_os = "openbsd"),
allow(dead_code)
)]
pub(crate) struct UnconfinedBackend;
#[cfg_attr(
any(target_os = "linux", target_os = "macos", target_os = "openbsd"),
allow(dead_code)
)]
impl UnconfinedBackend {
fn prepare(profile: SandboxProfile) -> Result<PrepareOutcome, VmError> {
super::unavailable(
SandboxMechanism::Unconfined,
SandboxMechanismAvailability::DoesNotConfine,
profile,
)
}
}
impl SandboxBackend for UnconfinedBackend {
fn name() -> &'static str {
"unconfined"
}
fn filesystem_mechanism() -> SandboxMechanism {
SandboxMechanism::Unconfined
}
fn available() -> bool {
false
}
fn prepare_std_command(
_program: &str,
_args: &[String],
_command: &mut Command,
_policy: &CapabilityPolicy,
profile: SandboxProfile,
) -> Result<PrepareOutcome, VmError> {
Self::prepare(profile)
}
fn prepare_tokio_command(
_program: &str,
_args: &[String],
_command: &mut tokio::process::Command,
_policy: &CapabilityPolicy,
profile: SandboxProfile,
) -> Result<PrepareOutcome, VmError> {
Self::prepare(profile)
}
}
pub fn active_backend_name() -> &'static str {
ActiveBackend::name()
}
pub fn active_backend_filesystem_mechanism() -> &'static str {
active_backend_mechanism().as_str()
}
pub fn active_backend_mechanism() -> SandboxMechanism {
ActiveBackend::filesystem_mechanism()
}
pub fn active_backend_filesystem_available() -> bool {
ActiveBackend::filesystem_available()
}
pub fn active_backend_available() -> bool {
ActiveBackend::available()
}