summary refs log tree commit diff
path: root/ripple
diff options
context:
space:
mode:
authoredef <edef@unfathomable.blue>2022-07-31 00:59:27 +0000
committeredef <edef@unfathomable.blue>2022-07-31 00:59:27 +0000
commitc3b2795fbda4091ed7e2baa3f2fbd915e14cdc82 (patch)
tree92912282433bd78c32d17e0e73e682033927d23b /ripple
parent39945afb70eb59ef348c512e8d3447027d13929c (diff)
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
Diffstat (limited to 'ripple')
-rw-r--r--ripple/minitrace/src/main.rs14
-rw-r--r--ripple/minitrace/src/pidfd.rs67
2 files changed, 78 insertions, 3 deletions
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 <edef@unfathomable.blue>
+// 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<PidFd> {
+		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<RawFd> {
+		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())
+		}
+	}
+}