pub(crate) mod fd;
mod landlock;
mod seccomp;
use crate::error::Error;
use crate::policy::AccessPolicy;
use crate::trap_fd::TrapFd;
use anyhow::Result;
use fd::close_inherited_fds;
use landlock::{enforce_access_policy, landlock_features};
use seccomp::NetworkFilter;
use std::ffi::{OsStr, OsString};
use std::os::unix::process::CommandExt;
use std::process::{self, Command};
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn execute(
policy: &AccessPolicy,
tool: &OsStr,
args: &[OsString],
trap_fd: &TrapFd,
) -> Result<()> {
let network = &policy.network_access;
let unrestricted_network = network.is_unrestricted();
let landlock_features = landlock_features()?;
if seccomp::needs_unix_socket_broker(&network.unix_socket_access) {
let engine = if landlock_features.resolve_unix {
"landlock"
} else {
"seccomp"
};
log::debug!("{engine}: Unix socket policy enabled");
}
let needs_fs_broker = seccomp::needs_filesystem_broker(policy) || trap_fd.is_enabled();
let needs_network_broker = !unrestricted_network
&& (network.local_tcp_bind
|| !network.connect_tcp_ports.is_empty()
|| seccomp::needs_unix_socket_broker(&network.unix_socket_access));
if needs_network_broker || needs_fs_broker {
let status = seccomp::run_broker(
policy,
landlock_features,
tool,
args,
needs_network_broker,
needs_fs_broker,
trap_fd,
)?;
trap_fd.close();
process::exit(status);
}
enforce_access_policy(policy, landlock_features)?;
if !unrestricted_network {
let filter = seccomp::network_filter(
NetworkFilter {
notify_bind: false,
notify_connect: false,
notify_filesystem: false,
unix_sockets: seccomp::unix_socket_filter(&network.unix_socket_access),
},
true,
)?;
filter.load()?;
}
close_inherited_fds();
let error = Command::new(tool).args(args).exec();
Err(Error::IoFailed(error).into())
}