std file descriptor protection
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing

This commit is contained in:
Jake Hillion 2022-05-20 17:15:14 +01:00
parent 8943d56a46
commit 95d3c06b31
5 changed files with 71 additions and 4 deletions

View File

@ -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)?;

View File

@ -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,
};

View File

@ -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);
}
}
}
}

View File

@ -119,6 +119,10 @@ pub enum Environment {
DomainName(String),
Procfs,
Stdin,
Stdout,
Stderr,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]

View File

@ -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 {