2022-02-11 16:27:45 +00:00
|
|
|
use std::fs::File;
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
|
|
|
|
|
|
|
use libc::{pid_t, syscall, SYS_clone3};
|
|
|
|
use nix::errno::Errno;
|
|
|
|
pub use nix::sched::CloneFlags;
|
|
|
|
use nix::sys::signal::Signal;
|
|
|
|
use nix::unistd::Pid;
|
|
|
|
|
|
|
|
pub struct CloneArgs<'a> {
|
|
|
|
pub flags: CloneFlags,
|
2022-03-28 16:46:30 +01:00
|
|
|
pub pidfd: Option<&'a mut Option<File>>,
|
|
|
|
pub child_tid: Option<&'a mut Option<Pid>>,
|
|
|
|
pub parent_tid: Option<&'a mut Option<Pid>>,
|
2022-02-11 16:27:45 +00:00
|
|
|
pub exit_signal: Option<Signal>,
|
|
|
|
pub stack: Option<&'a mut [u8]>,
|
|
|
|
pub set_tid: Option<&'a [Pid]>,
|
|
|
|
pub cgroup: Option<&'a File>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
2022-03-28 16:46:30 +01:00
|
|
|
struct CloneArgsFfi<'a> {
|
2022-02-11 16:27:45 +00:00
|
|
|
flags: u64,
|
|
|
|
pidfd: u64,
|
|
|
|
child_tid: u64,
|
|
|
|
parent_tid: u64,
|
|
|
|
exit_signal: u64,
|
|
|
|
stack: u64,
|
|
|
|
stack_size: u64,
|
|
|
|
tls: u64,
|
|
|
|
set_tid: u64,
|
|
|
|
set_tid_size: u64,
|
|
|
|
cgroup: u64,
|
|
|
|
|
|
|
|
phantom: PhantomData<&'a ()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a: 'b, 'b: 'c, 'c> CloneArgs<'a> {
|
|
|
|
pub fn new(flags: CloneFlags) -> CloneArgs<'a> {
|
|
|
|
CloneArgs {
|
|
|
|
flags,
|
|
|
|
|
|
|
|
pidfd: None,
|
|
|
|
|
|
|
|
child_tid: None,
|
|
|
|
parent_tid: None,
|
|
|
|
|
|
|
|
exit_signal: None,
|
|
|
|
|
|
|
|
stack: None,
|
|
|
|
set_tid: None,
|
|
|
|
cgroup: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-28 16:46:30 +01:00
|
|
|
fn process(
|
|
|
|
&'b mut self,
|
|
|
|
pidfd: &mut RawFd,
|
|
|
|
child_tid: &mut pid_t,
|
|
|
|
parent_tid: &mut pid_t,
|
|
|
|
) -> CloneArgsFfi<'c> {
|
|
|
|
CloneArgsFfi {
|
2022-02-11 16:27:45 +00:00
|
|
|
flags: self.flags.bits() as u64,
|
|
|
|
pidfd: self
|
|
|
|
.pidfd
|
|
|
|
.as_ref()
|
2022-03-28 16:46:30 +01:00
|
|
|
.map(|_| pidfd as *mut RawFd as u64)
|
2022-02-11 16:27:45 +00:00
|
|
|
.unwrap_or(0),
|
|
|
|
child_tid: self
|
|
|
|
.child_tid
|
|
|
|
.as_ref()
|
2022-03-28 16:46:30 +01:00
|
|
|
.map(|_| child_tid as *mut pid_t as u64)
|
2022-02-11 16:27:45 +00:00
|
|
|
.unwrap_or(0),
|
|
|
|
parent_tid: self
|
|
|
|
.parent_tid
|
|
|
|
.as_ref()
|
2022-03-28 16:46:30 +01:00
|
|
|
.map(|_| parent_tid as *mut pid_t as u64)
|
2022-02-11 16:27:45 +00:00
|
|
|
.unwrap_or(0),
|
|
|
|
exit_signal: self.exit_signal.map(|s| s as i32 as u64).unwrap_or(0),
|
|
|
|
stack: self
|
|
|
|
.stack
|
|
|
|
.as_mut()
|
|
|
|
.map(|s| s.as_mut_ptr() as u64)
|
|
|
|
.unwrap_or(0),
|
|
|
|
stack_size: self.stack.as_ref().map(|s| s.len() as u64).unwrap_or(0),
|
|
|
|
tls: 0,
|
|
|
|
set_tid: self
|
|
|
|
.set_tid
|
|
|
|
.as_ref()
|
|
|
|
.map(|s| s.as_ptr() as u64)
|
|
|
|
.unwrap_or(0),
|
|
|
|
set_tid_size: self.set_tid.as_ref().map(|s| s.len() as u64).unwrap_or(0),
|
|
|
|
cgroup: self.cgroup.map(|c| c.as_raw_fd() as u64).unwrap_or(0),
|
|
|
|
|
|
|
|
phantom: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-28 16:46:30 +01:00
|
|
|
unsafe fn finalise(&mut self, pidfd: RawFd, child_tid: pid_t, parent_tid: pid_t) {
|
2022-02-11 16:27:45 +00:00
|
|
|
if let Some(r) = &mut self.pidfd {
|
2022-03-28 16:46:30 +01:00
|
|
|
**r = Some(File::from_raw_fd(pidfd));
|
2022-02-11 16:27:45 +00:00
|
|
|
}
|
|
|
|
if let Some(r) = &mut self.child_tid {
|
2022-03-28 16:46:30 +01:00
|
|
|
**r = Some(Pid::from_raw(child_tid));
|
2022-02-11 16:27:45 +00:00
|
|
|
}
|
|
|
|
if let Some(r) = &mut self.parent_tid {
|
2022-03-28 16:46:30 +01:00
|
|
|
**r = Some(Pid::from_raw(parent_tid));
|
2022-02-11 16:27:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clone3(mut args: CloneArgs) -> nix::Result<Pid> {
|
2022-03-28 16:46:30 +01:00
|
|
|
let mut pidfd: RawFd = 0;
|
|
|
|
let mut child_tid: pid_t = 0;
|
|
|
|
let mut parent_tid: pid_t = 0;
|
2022-02-11 16:27:45 +00:00
|
|
|
|
2022-03-28 16:46:30 +01:00
|
|
|
let args_ffi: CloneArgsFfi = args.process(&mut pidfd, &mut child_tid, &mut parent_tid);
|
|
|
|
let result = unsafe { syscall(SYS_clone3, &args_ffi, std::mem::size_of_val(&args_ffi)) };
|
2022-02-11 16:27:45 +00:00
|
|
|
|
|
|
|
let out = Errno::result(result).map(|p| Pid::from_raw(p as i32))?;
|
|
|
|
|
2022-03-28 16:46:30 +01:00
|
|
|
// SAFETY: requested things have been filled by the kernel so are now valid for their type
|
|
|
|
unsafe {
|
|
|
|
args.finalise(pidfd, child_tid, parent_tid);
|
|
|
|
}
|
2022-02-11 16:27:45 +00:00
|
|
|
|
|
|
|
Ok(out)
|
|
|
|
}
|