pub use crate::stdlib::sandbox::{
active_backend_available, active_backend_filesystem_available,
active_backend_filesystem_mechanism, active_backend_mechanism, active_backend_mechanism_limits,
active_backend_name, active_workspace_process_env, apply_active_rustc_wrapper_policy,
apply_active_rustc_wrapper_policy_for_command, check_fs_path_scope,
check_git_metadata_path_scope, command_output, conformance, deterministic_message_locale_env,
enforce_process_cwd, enforcement, host_confinement, infer_process_sandbox_mechanism,
is_process_sandbox_signal, is_workspace_runtime_directory, process_spawn_error,
process_violation_error, push_process_sandbox_scope, render_policy_root, rustc_wrapper,
session_std_command, session_tokio_command, std_command_for, std_command_for_with_env_state,
tokio_command_for, tokio_command_for_with_env_state, validate_command_environment,
workspace_local_tmpdir, FsAccess, ProcessCommandConfig, ProcessSandboxAssessment,
ProcessSandboxDenialReporting, ProcessSandboxGrants, ProcessSandboxMechanism,
ProcessSandboxOperation, ProcessSandboxRefusal, ProcessSandboxReportingContext,
ProcessSandboxScope, ProcessSandboxScopeGuard, SandboxMechanism, SandboxMechanismAvailability,
SandboxMechanismUnavailable, SandboxRequirement, SandboxViolation, MESSAGE_LOCALE_OVERRIDE_ENV,
SANDBOX_CONFINEMENT_SCHEMA,
};
pub use crate::stdlib::git_topology::check_repository_metadata_scope;
pub use crate::stdlib::sandbox::command_output_with_declared_roots;
impl ProcessSandboxScope {
pub fn from_value(value: Option<&crate::VmValue>) -> Result<Self, crate::VmError> {
use crate::VmValue;
let invalid = |message: String| crate::VmError::TypeError(format!("sandbox: {message}"));
let map = match value {
None | Some(VmValue::Nil) => return Ok(Self::default()),
Some(VmValue::Dict(map)) => map,
Some(other) => {
return Err(invalid(format!("expected dict, got {}", other.type_name())))
}
};
let roots = match map.get("workspace_roots") {
None | Some(VmValue::Nil) => return Ok(Self::default()),
Some(VmValue::List(roots)) => roots,
Some(other) => {
return Err(invalid(format!(
"workspace_roots must be a list of strings, got {}",
other.type_name()
)))
}
};
let workspace_roots = roots
.iter()
.map(|root| match root {
VmValue::String(root) if !root.trim().is_empty() => Ok(root.to_string()),
_ => Err(invalid(
"workspace_roots entries must be nonempty strings".into(),
)),
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Self { workspace_roots })
}
}
pub use crate::stdlib::sandbox::self_confinement::{
confine_current_process, current_process_confinement, ProcessConfinement,
};
pub const NETNS_LAUNCH_SUBCOMMAND: &str = "netns-launch";
pub const NETNS_RULESET_FD_FLAG: &str = "--ruleset-fd";
pub const NETNS_SECCOMP_FLAG: &str = "--seccomp-hex";
pub const NETNS_CLOSE_FD_FLAG: &str = "--close-fd";
#[derive(Clone, Debug)]
pub struct DeviceMountFinalization {
pub descriptor: i32,
pub destination: std::path::PathBuf,
}
impl std::fmt::Display for DeviceMountFinalization {
fn fmt(&self, out: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(out, "{}:{}", self.descriptor, self.destination.display())
}
}
impl std::str::FromStr for DeviceMountFinalization {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let (descriptor, destination) = value
.split_once(':')
.ok_or("device finalization requires FD:absolute-path")?;
let descriptor = descriptor
.parse::<i32>()
.map_err(|_| "invalid device descriptor")?;
let destination = std::path::PathBuf::from(destination);
if descriptor < 3 || !destination.is_absolute() || value.contains('\0') {
return Err(
"device finalization requires an owned descriptor and absolute path".into(),
);
}
Ok(Self {
descriptor,
destination,
})
}
}
#[cfg(target_os = "linux")]
pub use crate::stdlib::sandbox::linux::keep_ruleset_across_exec;
#[cfg(target_os = "linux")]
pub(crate) use crate::stdlib::sandbox::linux::sealed_launch_bytes;
#[cfg(target_os = "linux")]
pub use crate::stdlib::sandbox::linux::DescriptorTransfer;
#[cfg(target_os = "linux")]
pub use crate::stdlib::sandbox::linux::{command_for_reexec, ReexecConfinement};
#[cfg(target_os = "linux")]
pub use crate::stdlib::sandbox::{
decode_seccomp_hex, transferable_confinement, TransferableConfinement,
};
pub fn push_sandbox_profile_override(
value: &str,
) -> Result<SandboxProfileOverrideGuard, crate::VmError> {
let profile = crate::orchestration::SandboxProfile::parse(value).ok_or_else(|| {
let expected = crate::orchestration::SandboxProfile::all()
.iter()
.map(|profile| format!("{:?}", profile.as_str()))
.collect::<Vec<_>>()
.join(", ");
crate::VmError::Thrown(crate::VmValue::String(arcstr::ArcStr::from(format!(
"unknown sandbox_profile {value:?}; expected one of {expected}"
))))
})?;
let mut policy = crate::orchestration::current_execution_policy().unwrap_or_default();
policy.sandbox_profile = profile;
crate::orchestration::push_execution_policy(policy);
Ok(SandboxProfileOverrideGuard {
_private: std::marker::PhantomData,
})
}
#[must_use = "dropping the guard immediately restores the surrounding sandbox profile"]
#[derive(Debug)]
pub struct SandboxProfileOverrideGuard {
_private: std::marker::PhantomData<*const ()>,
}
impl Drop for SandboxProfileOverrideGuard {
fn drop(&mut self) {
crate::orchestration::pop_execution_policy();
}
}
pub fn wrapped_spawn_io_error(exit_code: i32, stderr: &[u8]) -> Option<std::io::Error> {
crate::stdlib::sandbox::active_sandbox_policy()?;
if !active_backend_available() {
return None;
}
#[cfg(target_os = "macos")]
return macos_wrapped_spawn_io_error(exit_code, stderr);
#[cfg(not(target_os = "macos"))]
{
let _ = (exit_code, stderr);
None
}
}
#[cfg(target_os = "macos")]
pub(crate) fn macos_wrapped_spawn_io_error(
exit_code: i32,
stderr: &[u8],
) -> Option<std::io::Error> {
const EX_OSERR: i32 = 71;
const PREFIX: &str = "sandbox-exec: execvp() of '";
const SUFFIX: &str = "' failed: No such file or directory\n";
let stderr = std::str::from_utf8(stderr).ok()?;
if exit_code == EX_OSERR && stderr.starts_with(PREFIX) && stderr.ends_with(SUFFIX) {
return Some(std::io::Error::from_raw_os_error(libc::ENOENT));
}
None
}
#[cfg(all(test, target_os = "macos"))]
mod tests {
use super::macos_wrapped_spawn_io_error;
#[test]
fn wrapper_missing_program_is_typed_not_found() {
let error = macos_wrapped_spawn_io_error(
71,
b"sandbox-exec: execvp() of 'missing-command' failed: No such file or directory\n",
)
.expect("sandbox wrapper failure");
assert_eq!(error.kind(), std::io::ErrorKind::NotFound);
}
#[test]
fn genuine_exit_71_is_not_a_wrapper_failure() {
assert!(macos_wrapped_spawn_io_error(71, b"").is_none());
assert!(macos_wrapped_spawn_io_error(71, b"application failed\n").is_none());
}
}
#[cfg(test)]
mod profile_override_tests {
use crate::orchestration::{
current_execution_policy, pop_execution_policy, push_execution_policy, CapabilityPolicy,
SandboxProfile,
};
use super::push_sandbox_profile_override;
#[test]
fn per_call_override_changes_only_the_profile_and_restores_the_parent() {
let parent = CapabilityPolicy {
sandbox_profile: SandboxProfile::OsHardened,
workspace_roots: vec!["/workspace".to_string()],
tools: vec!["run_command".to_string()],
..CapabilityPolicy::default()
};
push_execution_policy(parent.clone());
{
let _guard = push_sandbox_profile_override("workspace_paths")
.expect("workspace_paths is a supported profile");
let current = current_execution_policy().expect("override policy");
assert_eq!(current.sandbox_profile, SandboxProfile::WorkspacePaths);
assert_eq!(current.workspace_roots, parent.workspace_roots);
assert_eq!(current.tools, parent.tools);
}
assert_eq!(current_execution_policy().expect("restored parent"), parent);
pop_execution_policy();
}
#[test]
fn per_call_override_rejects_unknown_profiles_without_mutating_policy() {
let parent = CapabilityPolicy {
sandbox_profile: SandboxProfile::Worktree,
..CapabilityPolicy::default()
};
push_execution_policy(parent.clone());
let error = push_sandbox_profile_override("wide_open")
.expect_err("unknown profiles must fail closed");
assert!(error.to_string().contains("unknown sandbox_profile"));
assert_eq!(
current_execution_policy().expect("unchanged parent"),
parent
);
pop_execution_policy();
}
}