summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMika Vatanen <blaind@blaind.net>2021-04-11 10:39:46 +0300
committerMika Vatanen <blaind@blaind.net>2021-08-09 20:29:44 +0300
commit1cbde2bb472507bdc6b84ec9ba6172dfcc2c01c5 (patch)
treeac2820918c5ff7b20f6d75d430cbefc21d9d5488
parent4c4be116f6414dbc9258f67102ea4b525efc037f (diff)
downloadnix-1cbde2bb472507bdc6b84ec9ba6172dfcc2c01c5.zip
Add PTRACE_INTERRUPT
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/ptrace/linux.rs18
-rw-r--r--test/sys/test_ptrace.rs42
3 files changed, 57 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d3594798..783d6675 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -90,6 +90,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- Added `sendfile64` (#[1439](https://github.com/nix-rust/nix/pull/1439))
- Added `MS_LAZYTIME` to `MsFlags`
(#[1437](https://github.com/nix-rust/nix/pull/1437))
+- Added `ptrace::interrupt` method for platforms that support `PTRACE_INTERRUPT`
+ (#[1422](https://github.com/nix-rust/nix/pull/1422))
### Changed
- Made `forkpty` unsafe, like `fork`
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
index 74a23e03..ef1dafbb 100644
--- a/src/sys/ptrace/linux.rs
+++ b/src/sys/ptrace/linux.rs
@@ -98,11 +98,9 @@ libc_enum!{
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
target_arch = "mips64"))))]
PTRACE_SETREGSET,
- #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
- target_arch = "mips64"))))]
+ #[cfg(target_os = "linux")]
PTRACE_SEIZE,
- #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
- target_arch = "mips64"))))]
+ #[cfg(target_os = "linux")]
PTRACE_INTERRUPT,
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
target_arch = "mips64"))))]
@@ -339,7 +337,7 @@ pub fn attach(pid: Pid) -> Result<()> {
/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)`
///
/// Attaches to the process specified in pid, making it a tracee of the calling process.
-#[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))]
+#[cfg(target_os = "linux")]
pub fn seize(pid: Pid, options: Options) -> Result<()> {
unsafe {
ptrace_other(
@@ -384,6 +382,16 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
}
}
+/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)`
+///
+/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)`
+#[cfg(target_os = "linux")]
+pub fn interrupt(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_INTERRUPT, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
+ }
+}
+
/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
///
/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index 985945d1..ceb39b9b 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -114,6 +114,48 @@ fn test_ptrace_cont() {
}
}
+#[cfg(target_os = "linux")]
+#[test]
+fn test_ptrace_interrupt() {
+ use nix::sys::ptrace;
+ use nix::sys::signal::Signal;
+ use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
+ use nix::unistd::fork;
+ use nix::unistd::ForkResult::*;
+ use std::thread::sleep;
+ use std::time::Duration;
+
+ require_capability!(CAP_SYS_PTRACE);
+
+ let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+
+ match unsafe{fork()}.expect("Error: Fork Failed") {
+ Child => {
+ loop {
+ sleep(Duration::from_millis(1000));
+ }
+
+ },
+ Parent { child } => {
+ ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();
+ ptrace::interrupt(child).unwrap();
+ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128)));
+ ptrace::syscall(child, None).unwrap();
+ assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
+ ptrace::detach(child, Some(Signal::SIGKILL)).unwrap();
+ match waitpid(child, None) {
+ Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
+ let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
+ while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
+ let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
+ }
+ }
+ _ => panic!("The process should have been killed"),
+ }
+ },
+ }
+}
+
// ptrace::{setoptions, getregs} are only available in these platforms
#[cfg(all(target_os = "linux",
any(target_arch = "x86_64",