From c3b2795fbda4091ed7e2baa3f2fbd915e14cdc82 Mon Sep 17 00:00:00 2001 From: edef Date: Sun, 31 Jul 2022 00:59:27 +0000 Subject: ripple/minitrace: use pidfd_send_signal over kill(2) This is slightly safer, protecting against mis-targeted kills due to PID reuse. Change-Id: I4800a47dfb52a49a2be1b9d7450f7f4704b8078b --- ripple/minitrace/src/main.rs | 14 +++++++-- ripple/minitrace/src/pidfd.rs | 67 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 ripple/minitrace/src/pidfd.rs (limited to 'ripple') diff --git a/ripple/minitrace/src/main.rs b/ripple/minitrace/src/main.rs index 5bc6e23..2d21f8b 100644 --- a/ripple/minitrace/src/main.rs +++ b/ripple/minitrace/src/main.rs @@ -3,7 +3,10 @@ // SPDX-License-Identifier: OSL-3.0 use { - crate::syscall_abi::{AtFlags, DirFd, MapFlags, SyscallEntry}, + crate::{ + pidfd::PidFd, + syscall_abi::{AtFlags, DirFd, MapFlags, SyscallEntry}, + }, anyhow::{bail, Context, Result}, bitflags::bitflags, nix::{ @@ -12,7 +15,7 @@ use { personality::{self, Persona}, ptrace, resource::{self, Resource as HostResource}, - signal::{kill, Signal as HostSignal}, + signal::Signal as HostSignal, wait::{waitpid, WaitPidFlag, WaitStatus}, }, unistd::Pid, @@ -29,6 +32,7 @@ use { }; mod maps_file; +mod pidfd; mod syscall_abi; // TODO(edef): consider implementing this in terms of TID? @@ -55,6 +59,7 @@ impl Tid { struct Process { tgid: Tgid, mem: File, + pidfd: PidFd, } impl Process { @@ -96,15 +101,18 @@ impl Process { status => bail!("unexpected child state: {status:?}"), } + let pidfd = PidFd::open(tgid.as_pid()).context("Couldn't open child pidfd")?; + Ok(Process { tgid, mem: File::open(format!("/proc/{}/mem", tgid.0)) .context("Couldn't open child memory")?, + pidfd, }) } fn terminate(&self) -> Result<()> { - match kill(self.tgid.as_pid(), HostSignal::SIGKILL) { + match self.pidfd.kill(HostSignal::SIGKILL) { Ok(()) | Err(nix::Error::ESRCH) => Ok(()), Err(err) => Err(anyhow::Error::from(err).context("Couldn't terminate child")), } diff --git a/ripple/minitrace/src/pidfd.rs b/ripple/minitrace/src/pidfd.rs new file mode 100644 index 0000000..ede0524 --- /dev/null +++ b/ripple/minitrace/src/pidfd.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: edef +// SPDX-License-Identifier: OSL-3.0 + +use { + nix::{libc::close, sys::signal::Signal, unistd::Pid, Result}, + std::os::unix::prelude::*, +}; + +#[derive(Debug)] +pub struct PidFd { + lower: RawFd, +} + +impl PidFd { + pub fn open(pid: Pid) -> Result { + lower::pidfd_open(pid).map(|lower| PidFd { lower }) + } + + pub fn kill(&self, signal: Signal) -> nix::Result<()> { + unsafe { lower::pidfd_send_signal(self.lower, signal) } + } +} + +impl Drop for PidFd { + fn drop(&mut self) { + unsafe { + close(self.lower); + } + } +} + +mod lower { + use { + nix::{ + libc::{c_int, c_uint, c_void, syscall, SYS_pidfd_open, SYS_pidfd_send_signal}, + sys::signal::Signal, + unistd::Pid, + Error, Result, + }, + std::{os::unix::prelude::*, ptr}, + }; + + pub fn pidfd_open(pid: Pid) -> Result { + unsafe { + let pid = pid.as_raw(); + let ret = syscall(SYS_pidfd_open, pid, 0); + if ret >= 0 { + Ok(ret as RawFd) + } else { + Err(Error::last()) + } + } + } + + pub unsafe fn pidfd_send_signal(pidfd: RawFd, signal: Signal) -> Result<()> { + let signal = signal as c_int; + let info: *const c_void = ptr::null(); + let flags: c_uint = 0; + + let ret = syscall(SYS_pidfd_send_signal, pidfd, signal, info, flags); + if ret == 0 { + Ok(()) + } else { + Err(Error::last()) + } + } +} -- cgit 1.4.1