std file descriptor protection #41
21
src/lib.rs
21
src/lib.rs
@ -8,7 +8,7 @@ mod void;
|
|||||||
|
|
||||||
use error::{Error, Result};
|
use error::{Error, Result};
|
||||||
use spawner::Spawner;
|
use spawner::Spawner;
|
||||||
use specification::Specification;
|
use specification::{Environment, Specification};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -25,13 +25,16 @@ pub struct RunArgs<'a> {
|
|||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
pub daemon: bool,
|
pub daemon: bool,
|
||||||
|
|
||||||
|
pub stdout: bool,
|
||||||
|
pub stderr: bool,
|
||||||
|
|
||||||
pub binary: &'a Path,
|
pub binary: &'a Path,
|
||||||
pub binary_args: Vec<&'a str>,
|
pub binary_args: Vec<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: &RunArgs) -> Result<i32> {
|
pub fn run(args: &RunArgs) -> Result<i32> {
|
||||||
// parse the specification
|
// 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) {
|
if m.extension().map(|e| e == "json") == Some(true) {
|
||||||
let f = std::fs::File::open(m)?;
|
let f = std::fs::File::open(m)?;
|
||||||
Ok(serde_json::from_reader(f)?)
|
Ok(serde_json::from_reader(f)?)
|
||||||
@ -45,6 +48,20 @@ pub fn run(args: &RunArgs) -> Result<i32> {
|
|||||||
debug!("specification read: {:?}", &spec);
|
debug!("specification read: {:?}", &spec);
|
||||||
spec.validate()?;
|
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
|
// create all the pipes
|
||||||
let (pipes, _) = spec.pipes();
|
let (pipes, _) = spec.pipes();
|
||||||
let pipes = create_pipes(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.")
|
.help("Detach the shim from all child processes and exit immediately.")
|
||||||
.takes_value(false),
|
.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(
|
||||||
Arg::new("binary")
|
Arg::new("binary")
|
||||||
.index(1)
|
.index(1)
|
||||||
@ -77,6 +89,10 @@ fn main() {
|
|||||||
spec: matches.value_of("spec").map(Path::new),
|
spec: matches.value_of("spec").map(Path::new),
|
||||||
debug: matches.is_present("debug"),
|
debug: matches.is_present("debug"),
|
||||||
daemon: matches.is_present("daemon"),
|
daemon: matches.is_present("daemon"),
|
||||||
|
|
||||||
|
stdout: matches.is_present("stdout"),
|
||||||
|
stderr: matches.is_present("stderr"),
|
||||||
|
|
||||||
binary,
|
binary,
|
||||||
binary_args,
|
binary_args,
|
||||||
};
|
};
|
||||||
|
@ -349,6 +349,16 @@ impl<'a> Spawner<'a> {
|
|||||||
Environment::Procfs => {
|
Environment::Procfs => {
|
||||||
builder.mount("/proc", "/proc").remount_proc();
|
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),
|
DomainName(String),
|
||||||
|
|
||||||
Procfs,
|
Procfs,
|
||||||
|
|
||||||
|
Stdin,
|
||||||
|
Stdout,
|
||||||
|
Stderr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]
|
#[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::collections::{HashMap, HashSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@ -14,7 +14,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use nix::fcntl::{FcntlArg, FdFlag};
|
use nix::fcntl::{FcntlArg, FdFlag};
|
||||||
use nix::mount::{mount, umount2, MntFlags, MsFlags};
|
use nix::mount::{mount, umount2, MntFlags, MsFlags};
|
||||||
use nix::sys::signal::{signal, SigHandler, Signal};
|
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;
|
use close_fds::CloseFdsBuilder;
|
||||||
|
|
||||||
@ -392,6 +392,26 @@ impl VoidBuilder {
|
|||||||
closer.closefrom(3);
|
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() {
|
for fd in keep.as_ref() {
|
||||||
let mut flags = FdFlag::from_bits_truncate(
|
let mut flags = FdFlag::from_bits_truncate(
|
||||||
nix::fcntl::fcntl(*fd, FcntlArg::F_GETFD).map_err(|e| Error::Nix {
|
nix::fcntl::fcntl(*fd, FcntlArg::F_GETFD).map_err(|e| Error::Nix {
|
||||||
|
Loading…
Reference in New Issue
Block a user