marked created fds as to keep
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-04-27 14:20:51 +01:00
parent 1486fc7418
commit ff32b48633
3 changed files with 97 additions and 67 deletions

View File

@ -1,5 +1,6 @@
use super::{Spawner, TriggerData}; use super::{Spawner, TriggerData};
use crate::specification::{Arg, FileSocket, Pipe}; use crate::specification::{Arg, FileSocket, Pipe};
use crate::void::VoidBuilder;
use crate::{Error, Result}; use crate::{Error, Result};
use std::ffi::CString; use std::ffi::CString;
@ -7,36 +8,42 @@ use std::fs::File;
use std::net::TcpListener; use std::net::TcpListener;
use std::os::unix::io::IntoRawFd; use std::os::unix::io::IntoRawFd;
/**
* perform initial processing with ambient authority
* for things like network sockets.
*/
pub struct PreparedArgs(Vec<PreparedArg>); pub struct PreparedArgs(Vec<PreparedArg>);
impl PreparedArgs { impl PreparedArgs {
pub fn prepare_ambient(args: &[Arg]) -> Result<Self> { /**
* perform initial processing with ambient authority
* for things like network sockets. update the builder
* with newly passed fds. the mutable call is allowed
* to use up things such as pipes and sockets.
*/
pub fn prepare_ambient_mut(
spawner: &mut Spawner,
builder: &mut VoidBuilder,
args: &[Arg],
) -> Result<Self> {
let mut v = Vec::with_capacity(args.len()); let mut v = Vec::with_capacity(args.len());
for arg in args { for arg in args {
v.push(PreparedArg::prepare_ambient(arg)?); v.push(PreparedArg::prepare_ambient_mut(spawner, builder, arg)?);
} }
Ok(PreparedArgs(v)) Ok(PreparedArgs(v))
} }
pub(super) fn prepare_void_mut( /**
self, * perform initial processing with ambient authority
spawner: &mut Spawner, * for things like network sockets. update the builder
entrypoint: &str, * with newly passed fds.
trigger: &mut TriggerData, */
) -> Result<Vec<CString>> { pub fn prepare_ambient(builder: &mut VoidBuilder, args: &[Arg]) -> Result<Self> {
let mut v = Vec::new(); let mut v = Vec::with_capacity(args.len());
for arg in self.0 { for arg in args {
v.extend(arg.prepare_void_mut(spawner, entrypoint, trigger)?) v.push(PreparedArg::prepare_ambient(builder, arg)?);
} }
Ok(v) Ok(PreparedArgs(v))
} }
pub(super) fn prepare_void( pub(super) fn prepare_void(
@ -65,10 +72,10 @@ enum PreparedArg {
File(File), File(File),
/// A chosen end of a named pipe /// A chosen end of a named pipe
Pipe(Pipe), Pipe(File),
/// File socket /// File socket
FileSocket(FileSocket), FileSocket(File),
/// A value specified by the trigger /// A value specified by the trigger
/// NOTE: Only valid if the trigger is of type Pipe(...) or FileSocket(...) /// NOTE: Only valid if the trigger is of type Pipe(...) or FileSocket(...)
@ -89,57 +96,60 @@ impl PreparedArg {
* Leave the remainder untouched so they can be processed in parallel * Leave the remainder untouched so they can be processed in parallel
* (in the child process) and to reduce authority * (in the child process) and to reduce authority
*/ */
fn prepare_ambient(arg: &Arg) -> Result<Self> { fn prepare_ambient_mut(
spawner: &mut Spawner,
builder: &mut VoidBuilder,
arg: &Arg,
) -> Result<Self> {
Ok(match arg { Ok(match arg {
Arg::File(path) => PreparedArg::File(File::open(path)?), Arg::Pipe(p) => {
let pipe = match p {
Pipe::Rx(s) => spawner.pipes.get_mut(s).unwrap().take_read(),
Pipe::Tx(s) => spawner.pipes.get_mut(s).unwrap().take_write(),
}?;
Arg::TcpListener { addr } => PreparedArg::TcpListener { builder.keep_fd(&pipe);
socket: TcpListener::bind(addr)?, PreparedArg::Pipe(pipe)
}, }
Arg::BinaryName => PreparedArg::BinaryName, Arg::FileSocket(s) => {
Arg::Entrypoint => PreparedArg::Entrypoint, let socket = match s {
Arg::Pipe(p) => PreparedArg::Pipe(p.clone()), FileSocket::Rx(s) => spawner.sockets.get_mut(s).unwrap().take_read(),
Arg::FileSocket(s) => PreparedArg::FileSocket(s.clone()), FileSocket::Tx(s) => spawner.sockets.get_mut(s).unwrap().take_write(),
Arg::Trigger => PreparedArg::Trigger, }?;
Arg::Trailing => PreparedArg::Trailing,
builder.keep_fd(&socket);
PreparedArg::FileSocket(socket)
}
arg => Self::prepare_ambient(builder, arg)?,
}) })
} }
/** fn prepare_ambient(builder: &mut VoidBuilder, arg: &Arg) -> Result<Self> {
* Complete argument preparation in the void Ok(match arg {
*/ Arg::Pipe(p) => return Err(Error::BadPipe(p.get_name().to_string())),
fn prepare_void_mut( Arg::FileSocket(s) => return Err(Error::BadFileSocket(s.get_name().to_string())),
self,
spawner: &mut Spawner,
entrypoint: &str,
trigger: &mut TriggerData,
) -> Result<Vec<CString>> {
match self {
PreparedArg::Pipe(p) => match p {
Pipe::Rx(s) => {
let pipe = spawner.pipes.get_mut(&s).unwrap().take_read()?;
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
}
Pipe::Tx(s) => {
let pipe = spawner.pipes.get_mut(&s).unwrap().take_write()?;
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
}
},
PreparedArg::FileSocket(s) => match s { Arg::File(path) => {
FileSocket::Rx(s) => { let fd = File::open(path)?;
let pipe = spawner.sockets.get_mut(&s).unwrap().take_read()?; builder.keep_fd(&fd);
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
}
FileSocket::Tx(s) => {
let pipe = spawner.sockets.get_mut(&s).unwrap().take_write()?;
Ok(vec![CString::new(pipe.into_raw_fd().to_string()).unwrap()])
}
},
arg => arg.prepare_void(spawner, entrypoint, trigger), PreparedArg::File(fd)
} }
Arg::TcpListener { addr } => {
let socket = TcpListener::bind(addr)?;
builder.keep_fd(&socket);
PreparedArg::TcpListener { socket }
}
Arg::BinaryName => PreparedArg::BinaryName,
Arg::Entrypoint => PreparedArg::Entrypoint,
Arg::Trigger => PreparedArg::Trigger,
Arg::Trailing => PreparedArg::Trailing,
})
} }
/** /**
@ -155,8 +165,10 @@ impl PreparedArg {
PreparedArg::BinaryName => Ok(vec![CString::new(spawner.binary).unwrap()]), PreparedArg::BinaryName => Ok(vec![CString::new(spawner.binary).unwrap()]),
PreparedArg::Entrypoint => Ok(vec![CString::new(entrypoint).unwrap()]), PreparedArg::Entrypoint => Ok(vec![CString::new(entrypoint).unwrap()]),
PreparedArg::Pipe(p) => Err(Error::BadPipe(p.get_name().to_string())), PreparedArg::Pipe(p) => Ok(vec![CString::new(p.into_raw_fd().to_string()).unwrap()]),
PreparedArg::FileSocket(s) => Err(Error::BadFileSocket(s.get_name().to_string())), PreparedArg::FileSocket(s) => {
Ok(vec![CString::new(s.into_raw_fd().to_string()).unwrap()])
}
PreparedArg::File(f) => Ok(vec![CString::new(f.into_raw_fd().to_string()).unwrap()]), PreparedArg::File(f) => Ok(vec![CString::new(f.into_raw_fd().to_string()).unwrap()]),

View File

@ -68,11 +68,12 @@ impl<'a> Spawner<'a> {
self.prepare_env(&mut builder, &entrypoint.environment); self.prepare_env(&mut builder, &entrypoint.environment);
let args = PreparedArgs::prepare_ambient(&entrypoint.args)?; let args =
PreparedArgs::prepare_ambient_mut(self, &mut builder, &entrypoint.args)?;
let closure = || { let closure = || {
let args = args let args = args
.prepare_void_mut(self, name, &mut TriggerData::None) .prepare_void(self, name, &mut TriggerData::None)
.unwrap(); .unwrap();
if let Err(e) = unistd::execv(&CString::new("/entrypoint").unwrap(), &args) if let Err(e) = unistd::execv(&CString::new("/entrypoint").unwrap(), &args)
@ -162,7 +163,7 @@ impl<'a> Spawner<'a> {
} }
} }
let args = PreparedArgs::prepare_ambient(&spec.args)?; let args = PreparedArgs::prepare_ambient(&mut builder, &spec.args)?;
let closure = let closure =
|| { || {
@ -226,7 +227,7 @@ impl<'a> Spawner<'a> {
} }
} }
let args = PreparedArgs::prepare_ambient(&spec.args)?; let args = PreparedArgs::prepare_ambient(&mut builder, &spec.args)?;
let closure = || { let closure = || {
let args = args let args = args

View File

@ -8,6 +8,7 @@ use std::fs;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use nix::fcntl::{FcntlArg, FdFlag};
use nix::mount::{mount, umount2, MntFlags, MsFlags}; use nix::mount::{mount, umount2, MntFlags, MsFlags};
use nix::sched::unshare; use nix::sched::unshare;
use nix::sys::signal::{signal, SigHandler, Signal}; use nix::sys::signal::{signal, SigHandler, Signal};
@ -103,6 +104,22 @@ impl VoidBuilder {
closer.closefrom(3); closer.closefrom(3);
} }
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 {
msg: "fcntl",
src: e,
})?,
);
flags.remove(FdFlag::FD_CLOEXEC);
nix::fcntl::fcntl(*fd, FcntlArg::F_SETFD(flags)).map_err(|e| Error::Nix {
msg: "fcntl",
src: e,
})?;
}
Ok(()) Ok(())
} }