#![forbid(unsafe_code)]
use std::{
env,
ffi::OsString,
process::{Command, ExitCode},
};
use syd::{
config::{ENV_SH, SYD_SH},
confine::{confine_mdwe, confine_scmp_wx_all, run_cmd},
};
#[cfg(all(
not(coverage),
not(feature = "prof"),
not(target_os = "android"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;
syd::main! {
use lexopt::prelude::*;
syd::set_sigpipe_dfl()?;
let mut opt_mdwe = false;
let mut opt_scmp = false;
let mut opt_cmd = env::var_os(ENV_SH).unwrap_or(OsString::from(SYD_SH));
let mut opt_arg = Vec::new();
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('h') => {
help();
return Ok(ExitCode::SUCCESS);
}
Short('m') => opt_mdwe = true,
Short('s') => opt_scmp = true,
Value(prog) => {
opt_cmd = prog;
opt_arg.extend(parser.raw_args()?);
}
_ => return Err(arg.unexpected().into()),
}
}
let opt_mdwe_fatal = opt_mdwe;
if !opt_mdwe && !opt_scmp {
opt_mdwe = true;
opt_scmp = true;
}
if opt_mdwe {
if let Err(errno) = confine_mdwe(false) {
eprintln!("prctl failed to set Memory-Deny-Write-Execute: {errno}!");
if opt_mdwe_fatal {
return Err(errno.into());
}
}
}
if opt_scmp {
if let Err(error) = confine_scmp_wx_all() {
eprintln!("seccomp failed to set W^X restrictions: {error}!");
return Err(error);
}
}
let mut cmd = Command::new(opt_cmd);
let cmd = cmd.args(opt_arg);
Ok(ExitCode::from(run_cmd(cmd)))
}
fn help() {
println!("Usage: syd-mdwe [-hms] {{command [args..]}}");
println!("Run a command under Memory-Deny-Write-Execute protections.");
println!("Use -m to enable protections using prctl(2) PR_SET_MDWE (default).");
println!("Use -s to enable protections using seccomp(2) (use with -m to enable both).");
}