working on forking
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
937921aae6
commit
61bfa35549
96
src/fork.rs
96
src/fork.rs
@ -11,8 +11,8 @@ use std::panic::UnwindSafe;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::future::poll_fn;
|
||||
use futures::io::AsyncRead;
|
||||
use nix::errno::Errno;
|
||||
|
||||
use crate::syscall::SyscallStatus;
|
||||
use crate::tools::Fd;
|
||||
@ -20,16 +20,12 @@ use crate::{libc_try, libc_wrap};
|
||||
|
||||
pub async fn forking_syscall<F>(func: F) -> io::Result<SyscallStatus>
|
||||
where
|
||||
F: FnOnce() -> io::Result<SyscallStatus> + UnwindSafe,
|
||||
F: FnOnce() -> Result<i64, Errno> + UnwindSafe,
|
||||
{
|
||||
let mut fork = Fork::new(func)?;
|
||||
let mut buf = [0u8; 10];
|
||||
|
||||
use futures::io::AsyncReadExt;
|
||||
fork.read_exact(&mut buf).await?;
|
||||
let result = fork.get_result().await?;
|
||||
fork.wait()?;
|
||||
|
||||
Ok(SyscallStatus::Err(libc::ENOENT))
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub struct Fork {
|
||||
@ -47,53 +43,47 @@ impl Drop for Fork {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct Data {
|
||||
val: i64,
|
||||
error: i32,
|
||||
}
|
||||
|
||||
impl Fork {
|
||||
pub fn new<F>(func: F) -> io::Result<Self>
|
||||
where
|
||||
F: FnOnce() -> io::Result<SyscallStatus> + UnwindSafe,
|
||||
F: FnOnce() -> Result<i64, Errno> + UnwindSafe,
|
||||
{
|
||||
let mut pipe: [c_int; 2] = [0, 0];
|
||||
libc_try!(unsafe { libc::pipe2(pipe.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) });
|
||||
let (pipe_r, pipe_w) = (Fd(pipe[0]), Fd(pipe[1]));
|
||||
|
||||
let pipe_r = match crate::tools::GenericStream::from_fd(pipe_r) {
|
||||
Ok(o) => o,
|
||||
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err.to_string())),
|
||||
};
|
||||
|
||||
let pid = libc_try!(unsafe { libc::fork() });
|
||||
if pid == 0 {
|
||||
std::mem::drop(pipe_r);
|
||||
let mut pipe_w = unsafe { std::fs::File::from_raw_fd(pipe_w.into_raw_fd()) };
|
||||
|
||||
let _ = std::panic::catch_unwind(move || {
|
||||
let mut buf = [0u8; 10];
|
||||
let out = match func() {
|
||||
Ok(val) => Data {
|
||||
val,
|
||||
error: 0,
|
||||
},
|
||||
Err(error) => Data {
|
||||
val: -1,
|
||||
error: error as _,
|
||||
},
|
||||
};
|
||||
|
||||
match func() {
|
||||
Ok(SyscallStatus::Ok(value)) => unsafe {
|
||||
std::ptr::write(buf.as_mut_ptr().add(1) as *mut i64, value);
|
||||
},
|
||||
Ok(SyscallStatus::Err(value)) => {
|
||||
buf[0] = 1;
|
||||
unsafe {
|
||||
std::ptr::write(buf.as_mut_ptr().add(1) as *mut i32, value);
|
||||
}
|
||||
}
|
||||
Err(err) => match err.raw_os_error() {
|
||||
Some(err) => {
|
||||
buf[0] = 2;
|
||||
unsafe {
|
||||
std::ptr::write(buf.as_mut_ptr().add(1) as *mut i32, err);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
buf[0] = 3;
|
||||
}
|
||||
},
|
||||
}
|
||||
let slice = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
&out as *const Data as *const u8,
|
||||
std::mem::size_of::<Data>(),
|
||||
)
|
||||
};
|
||||
|
||||
use std::io::Write;
|
||||
match pipe_w.write_all(&buf) {
|
||||
match pipe_w.write_all(slice) {
|
||||
Ok(()) => unsafe { libc::_exit(0) },
|
||||
Err(_) => unsafe { libc::_exit(1) },
|
||||
}
|
||||
@ -103,6 +93,11 @@ impl Fork {
|
||||
}
|
||||
}
|
||||
|
||||
let pipe_r = match crate::tools::GenericStream::from_fd(pipe_r) {
|
||||
Ok(o) => o,
|
||||
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err.to_string())),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
pid: Some(pid),
|
||||
out: pipe_r,
|
||||
@ -111,9 +106,9 @@ impl Fork {
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<()> {
|
||||
let my_pid = self.pid.take().unwrap();
|
||||
let mut status: c_int = -1;
|
||||
|
||||
loop {
|
||||
let mut status: c_int = -1;
|
||||
match libc_wrap!(unsafe { libc::waitpid(my_pid, &mut status, 0) }) {
|
||||
Ok(pid) if pid == my_pid => break,
|
||||
Ok(_other) => continue,
|
||||
@ -122,11 +117,28 @@ impl Fork {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
if status != 0 {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "error in child process"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn async_read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
poll_fn(|cx| Pin::new(&mut *self).poll_read(cx, buf)).await
|
||||
pub async fn get_result(&mut self) -> io::Result<SyscallStatus> {
|
||||
use futures::io::AsyncReadExt;
|
||||
|
||||
let mut data: Data = unsafe { std::mem::zeroed() };
|
||||
self.read_exact(unsafe {
|
||||
std::slice::from_raw_parts_mut(
|
||||
&mut data as *mut Data as *mut u8,
|
||||
std::mem::size_of::<Data>(),
|
||||
)
|
||||
}).await?;
|
||||
if data.error == 0 {
|
||||
Ok(SyscallStatus::Ok(data.val))
|
||||
} else {
|
||||
Ok(SyscallStatus::Err(data.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,13 +295,8 @@ impl ProxyMessageBuffer {
|
||||
}
|
||||
|
||||
/// Checked way to get a `mode_t` argument.
|
||||
pub fn arg_mode_t(&self, arg: u32) -> Result<nix::sys::stat::Mode, Error> {
|
||||
use nix::sys::stat;
|
||||
|
||||
stat::Mode::from_bits(
|
||||
stat::mode_t::try_from(self.arg(arg)?).map_err(|_| Error::from(Errno::EINVAL))?,
|
||||
)
|
||||
.ok_or_else(|| Errno::EINVAL.into())
|
||||
pub fn arg_mode_t(&self, arg: u32) -> Result<nix::sys::stat::mode_t, Error> {
|
||||
nix::sys::stat::mode_t::try_from(self.arg(arg)?).map_err(|_| Error::from(Errno::EINVAL))
|
||||
}
|
||||
|
||||
/// Checked way to get a `dev_t` argument.
|
||||
|
@ -44,10 +44,10 @@ impl PidFd {
|
||||
}
|
||||
|
||||
pub fn fd_cwd(&self) -> io::Result<Fd> {
|
||||
self.fd(b"cwd", libc::O_DIRECTORY)
|
||||
self.fd(b"cwd\0", libc::O_DIRECTORY)
|
||||
}
|
||||
|
||||
pub fn fd_num(&self, num: RawFd, flags: c_int) -> io::Result<Fd> {
|
||||
self.fd(format!("fd/{}", num).as_bytes(), flags)
|
||||
self.fd(format!("fd/{}\0", num).as_bytes(), flags)
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use failure::Error;
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::stat;
|
||||
|
||||
use crate::fork::forking_syscall;
|
||||
use crate::lxcseccomp::ProxyMessageBuffer;
|
||||
use crate::syscall::SyscallStatus;
|
||||
use crate::tools::Fd;
|
||||
@ -27,9 +28,11 @@ pub async fn mknodat(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> {
|
||||
async fn do_mknodat(
|
||||
_dirfd: Fd,
|
||||
_pathname: CString,
|
||||
_mode: stat::Mode,
|
||||
_mode: stat::mode_t,
|
||||
_dev: stat::dev_t,
|
||||
) -> Result<SyscallStatus, Error> {
|
||||
println!("=> Responding with ENOENT");
|
||||
Err(Errno::ENOENT.into())
|
||||
Ok(forking_syscall(move || {
|
||||
Err(Errno::ENOENT)
|
||||
}).await?)
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ macro_rules! file_descriptor_impl {
|
||||
($type:ty) => {
|
||||
impl Drop for $type {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
libc::close(self.0);
|
||||
if self.0 >= 0 {
|
||||
unsafe {
|
||||
libc::close(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user