std file descriptor protection #41
21
src/lib.rs
21
src/lib.rs
@ -8,7 +8,7 @@ mod void;
|
||||
|
||||
use error::{Error, Result};
|
||||
use spawner::Spawner;
|
||||
use specification::Specification;
|
||||
use specification::{Environment, Specification};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
@ -25,13 +25,16 @@ pub struct RunArgs<'a> {
|
||||
pub debug: bool,
|
||||
pub daemon: bool,
|
||||
|
||||
pub stdout: bool,
|
||||
pub stderr: bool,
|
||||
|
||||
pub binary: &'a Path,
|
||||
pub binary_args: Vec<&'a str>,
|
||||
}
|
||||
|
||||
pub fn run(args: &RunArgs) -> Result<i32> {
|
||||
// parse the specification
|
||||
let spec: Specification = if let Some(m) = args.spec {
|
||||
let mut spec: Specification = if let Some(m) = args.spec {
|
||||
if m.extension().map(|e| e == "json") == Some(true) {
|
||||
let f = std::fs::File::open(m)?;
|
||||
Ok(serde_json::from_reader(f)?)
|
||||
@ -45,6 +48,20 @@ pub fn run(args: &RunArgs) -> Result<i32> {
|
||||
debug!("specification read: {:?}", &spec);
|
||||
spec.validate()?;
|
||||
|
||||
if args.stdout {
|
||||
debug!("forwarding stdout");
|
||||
for entrypoint in &mut spec.entrypoints.values_mut() {
|
||||
entrypoint.environment.insert(Environment::Stdout);
|
||||
}
|
||||
}
|
||||
|
||||
if args.stderr {
|
||||
debug!("forwarding stderr");
|
||||
for entrypoint in &mut spec.entrypoints.values_mut() {
|
||||
entrypoint.environment.insert(Environment::Stderr);
|
||||
}
|
||||
}
|
||||
|
||||
// create all the pipes
|
||||
let (pipes, _) = spec.pipes();
|
||||
let pipes = create_pipes(pipes)?;
|
||||
|
16
src/main.rs
16
src/main.rs
@ -41,6 +41,18 @@ fn main() {
|
||||
.help("Detach the shim from all child processes and exit immediately.")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("stdout")
|
||||
.long("stdout")
|
||||
.help("Allow all spawned processes access to stdout (useful for debugging).")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("stderr")
|
||||
.long("stderr")
|
||||
.help("Allow all spawned processes access to stderr (useful for debugging).")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("binary")
|
||||
.index(1)
|
||||
@ -77,6 +89,10 @@ fn main() {
|
||||
spec: matches.value_of("spec").map(Path::new),
|
||||
debug: matches.is_present("debug"),
|
||||
daemon: matches.is_present("daemon"),
|
||||
|
||||
stdout: matches.is_present("stdout"),
|
||||
stderr: matches.is_present("stderr"),
|
||||
|
||||
binary,
|
||||
binary_args,
|
||||
};
|
||||
|
@ -349,6 +349,16 @@ impl<'a> Spawner<'a> {
|
||||
Environment::Procfs => {
|
||||
builder.mount("/proc", "/proc").remount_proc();
|
||||
}
|
||||
|
||||
Environment::Stdin => {
|
||||
builder.keep_fd(&0);
|
||||
}
|
||||
Environment::Stdout => {
|
||||
builder.keep_fd(&1);
|
||||
}
|
||||
Environment::Stderr => {
|
||||
builder.keep_fd(&2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +119,10 @@ pub enum Environment {
|
||||
DomainName(String),
|
||||
|
||||
Procfs,
|
||||
|
||||
Stdin,
|
||||
Stdout,
|
||||
Stderr,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]
|
||||
|
24
src/void.rs
24
src/void.rs
@ -6,7 +6,7 @@ use crate::{Error, Result};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -14,7 +14,7 @@ use std::path::{Path, PathBuf};
|
||||
use nix::fcntl::{FcntlArg, FdFlag};
|
||||
use nix::mount::{mount, umount2, MntFlags, MsFlags};
|
||||
use nix::sys::signal::{signal, SigHandler, Signal};
|
||||
use nix::unistd::{close, getgid, getuid, pivot_root, sethostname, Gid, Pid, Uid};
|
||||
use nix::unistd::{close, dup2, getgid, getuid, pivot_root, sethostname, Gid, Pid, Uid};
|
||||
|
||||
use close_fds::CloseFdsBuilder;
|
||||
|
||||
@ -392,6 +392,26 @@ impl VoidBuilder {
|
||||
closer.closefrom(3);
|
||||
}
|
||||
|
||||
// overwrite stdin/stdout/stderr without closing
|
||||
{
|
||||
let mut nullfd: Option<File> = None;
|
||||
for stdfd in &[0, 1, 2] {
|
||||
if !keep.contains(stdfd) {
|
||||
let fd = nullfd
|
||||
.take()
|
||||
.map(Ok)
|
||||
.unwrap_or_else(|| File::open("/dev/null"))?;
|
||||
|
||||
dup2(fd.as_raw_fd(), *stdfd).map_err(|e| Error::Nix {
|
||||
msg: "dup2",
|
||||
src: e,
|
||||
})?;
|
||||
|
||||
nullfd = Some(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for fd in keep.as_ref() {
|
||||
let mut flags = FdFlag::from_bits_truncate(
|
||||
nix::fcntl::fcntl(*fd, FcntlArg::F_GETFD).map_err(|e| Error::Nix {
|
||||
|
Loading…
Reference in New Issue
Block a user