Merge pull request #605 from mahkoh/jorth/clone3
clone3: don't use clone3 syscall directly
This commit is contained in:
commit
ddd96b9ad8
1 changed files with 47 additions and 64 deletions
|
|
@ -8,22 +8,6 @@ use {
|
||||||
uapi::{Msghdr, MsghdrMut, OwnedFd, c},
|
uapi::{Msghdr, MsghdrMut, OwnedFd, c},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone)]
|
|
||||||
#[expect(non_camel_case_types, dead_code)]
|
|
||||||
struct clone_args {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Forked {
|
pub enum Forked {
|
||||||
Parent { pid: c::pid_t, pidfd: OwnedFd },
|
Parent { pid: c::pid_t, pidfd: OwnedFd },
|
||||||
Child { pidfd: Option<OwnedFd> },
|
Child { pidfd: Option<OwnedFd> },
|
||||||
|
|
@ -32,33 +16,25 @@ pub enum Forked {
|
||||||
const REAPER_VAR: &str = "JAY_REAPER_PID";
|
const REAPER_VAR: &str = "JAY_REAPER_PID";
|
||||||
|
|
||||||
pub fn fork_with_pidfd(pidfd_for_child: bool) -> Result<Forked, ForkerError> {
|
pub fn fork_with_pidfd(pidfd_for_child: bool) -> Result<Forked, ForkerError> {
|
||||||
let mut pidfd: c::c_int = 0;
|
|
||||||
let mut args = clone_args {
|
|
||||||
flags: c::CLONE_PIDFD as u64,
|
|
||||||
pidfd: (&mut pidfd as *mut c::c_int) as _,
|
|
||||||
exit_signal: c::SIGCHLD as _,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let mut child_pidfd = None;
|
let mut child_pidfd = None;
|
||||||
if pidfd_for_child {
|
if pidfd_for_child {
|
||||||
child_pidfd = Some(uapi::pidfd_open(uapi::getpid(), 0).unwrap());
|
child_pidfd = Some(uapi::pidfd_open(uapi::getpid(), 0).unwrap());
|
||||||
}
|
}
|
||||||
|
let (p, c) = uapi::socketpair(c::AF_UNIX, c::SOCK_DGRAM | c::SOCK_CLOEXEC, 0)
|
||||||
|
.map_err(|e| ForkerError::Socketpair(e.into()))?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let pid = c::syscall(
|
let pid = uapi::fork().map_err(|e| ForkerError::Fork(e.into()))?;
|
||||||
c::SYS_clone3,
|
|
||||||
&mut args as *const _ as usize,
|
|
||||||
size_of::<clone_args>(),
|
|
||||||
);
|
|
||||||
if let Err(e) = uapi::map_err!(pid) {
|
|
||||||
return Err(ForkerError::Fork(e.into()));
|
|
||||||
}
|
|
||||||
let res = if pid == 0 {
|
let res = if pid == 0 {
|
||||||
|
drop(p);
|
||||||
env::remove_var(REAPER_VAR);
|
env::remove_var(REAPER_VAR);
|
||||||
|
let pidfd = uapi::pidfd_open(uapi::getpid(), 0).unwrap();
|
||||||
|
send_pidfd(&c, &pidfd);
|
||||||
Forked::Child { pidfd: child_pidfd }
|
Forked::Child { pidfd: child_pidfd }
|
||||||
} else {
|
} else {
|
||||||
|
drop(c);
|
||||||
Forked::Parent {
|
Forked::Parent {
|
||||||
pid: pid as _,
|
pid: pid as _,
|
||||||
pidfd: OwnedFd::new(pidfd),
|
pidfd: recv_pidfd(&p)?,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|
@ -71,47 +47,17 @@ pub fn double_fork() -> Result<Option<OwnedFd>, ForkerError> {
|
||||||
match fork_with_pidfd(false)? {
|
match fork_with_pidfd(false)? {
|
||||||
Forked::Parent { pid, .. } => {
|
Forked::Parent { pid, .. } => {
|
||||||
drop(c);
|
drop(c);
|
||||||
let mut buf = [MaybeUninit::<u8>::uninit(); 128];
|
|
||||||
let iov: &mut [&mut [u8]] = &mut [];
|
|
||||||
let mut msghdr = MsghdrMut {
|
|
||||||
iov,
|
|
||||||
control: Some(&mut buf),
|
|
||||||
name: uapi::sockaddr_none_mut(),
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
let _wait = OnDrop(|| {
|
let _wait = OnDrop(|| {
|
||||||
let _ = uapi::waitpid(pid, 0);
|
let _ = uapi::waitpid(pid, 0);
|
||||||
});
|
});
|
||||||
let (_, _, mut ctrl) = uapi::recvmsg(p.raw(), &mut msghdr, c::MSG_CMSG_CLOEXEC)
|
recv_pidfd(&p).map(Some)
|
||||||
.map_err(|e| ForkerError::RecvPidfd(e.into()))?;
|
|
||||||
let (_, hdr, data) =
|
|
||||||
uapi::cmsg_read(&mut ctrl).map_err(|e| ForkerError::CmsgRead(e.into()))?;
|
|
||||||
if hdr.cmsg_level != c::SOL_SOCKET || hdr.cmsg_type != c::SCM_RIGHTS {
|
|
||||||
return Err(ForkerError::InvalidCmsg);
|
|
||||||
}
|
|
||||||
let Ok(fd) = uapi::pod_read(data) else {
|
|
||||||
return Err(ForkerError::InvalidCmsg);
|
|
||||||
};
|
|
||||||
Ok(Some(OwnedFd::new(fd)))
|
|
||||||
}
|
}
|
||||||
Forked::Child { .. } => {
|
Forked::Child { .. } => {
|
||||||
drop(p);
|
drop(p);
|
||||||
if let Ok(f) = fork_with_pidfd(true) {
|
if let Ok(f) = fork_with_pidfd(true) {
|
||||||
match f {
|
match f {
|
||||||
Forked::Parent { pidfd, .. } => {
|
Forked::Parent { pidfd, .. } => {
|
||||||
let pidfd = pidfd.raw();
|
send_pidfd(&c, &pidfd);
|
||||||
let mut buf = [MaybeUninit::uninit(); 128];
|
|
||||||
let mut hdr: c::cmsghdr = uapi::pod_zeroed();
|
|
||||||
hdr.cmsg_level = c::SOL_SOCKET;
|
|
||||||
hdr.cmsg_type = c::SCM_RIGHTS;
|
|
||||||
let _ = uapi::cmsg_write(&mut &mut buf[..], hdr, &pidfd);
|
|
||||||
let iov: &[&[u8]] = &[];
|
|
||||||
let msghdr = Msghdr {
|
|
||||||
iov,
|
|
||||||
control: Some(&buf[..uapi::cmsg_space(size_of_val(&pidfd))]),
|
|
||||||
name: uapi::sockaddr_none_ref(),
|
|
||||||
};
|
|
||||||
let _ = uapi::sendmsg(c.raw(), &msghdr, 0);
|
|
||||||
}
|
}
|
||||||
Forked::Child { pidfd } => {
|
Forked::Child { pidfd } => {
|
||||||
let pidfd = pidfd.unwrap();
|
let pidfd = pidfd.unwrap();
|
||||||
|
|
@ -176,3 +122,40 @@ fn set_deathsig() {
|
||||||
c::prctl(c::PR_SET_PDEATHSIG, c::SIGKILL as c::c_ulong);
|
c::prctl(c::PR_SET_PDEATHSIG, c::SIGKILL as c::c_ulong);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_pidfd(socket: &OwnedFd, pidfd: &OwnedFd) {
|
||||||
|
let pidfd = pidfd.raw();
|
||||||
|
let mut buf = [MaybeUninit::uninit(); 128];
|
||||||
|
let mut hdr: c::cmsghdr = uapi::pod_zeroed();
|
||||||
|
hdr.cmsg_level = c::SOL_SOCKET;
|
||||||
|
hdr.cmsg_type = c::SCM_RIGHTS;
|
||||||
|
let _ = uapi::cmsg_write(&mut &mut buf[..], hdr, &pidfd);
|
||||||
|
let iov: &[&[u8]] = &[];
|
||||||
|
let msghdr = Msghdr {
|
||||||
|
iov,
|
||||||
|
control: Some(&buf[..uapi::cmsg_space(size_of_val(&pidfd))]),
|
||||||
|
name: uapi::sockaddr_none_ref(),
|
||||||
|
};
|
||||||
|
let _ = uapi::sendmsg(socket.raw(), &msghdr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_pidfd(socket: &OwnedFd) -> Result<OwnedFd, ForkerError> {
|
||||||
|
let mut buf = [MaybeUninit::<u8>::uninit(); 128];
|
||||||
|
let iov: &mut [&mut [u8]] = &mut [];
|
||||||
|
let mut msghdr = MsghdrMut {
|
||||||
|
iov,
|
||||||
|
control: Some(&mut buf),
|
||||||
|
name: uapi::sockaddr_none_mut(),
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
let (_, _, mut ctrl) = uapi::recvmsg(socket.raw(), &mut msghdr, c::MSG_CMSG_CLOEXEC)
|
||||||
|
.map_err(|e| ForkerError::RecvPidfd(e.into()))?;
|
||||||
|
let (_, hdr, data) = uapi::cmsg_read(&mut ctrl).map_err(|e| ForkerError::CmsgRead(e.into()))?;
|
||||||
|
if hdr.cmsg_level != c::SOL_SOCKET || hdr.cmsg_type != c::SCM_RIGHTS {
|
||||||
|
return Err(ForkerError::InvalidCmsg);
|
||||||
|
}
|
||||||
|
let Ok(fd) = uapi::pod_read(data) else {
|
||||||
|
return Err(ForkerError::InvalidCmsg);
|
||||||
|
};
|
||||||
|
Ok(OwnedFd::new(fd))
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue