diff options
-rw-r--r-- | CHANGELOG.md | 17 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/macros.rs | 128 | ||||
-rw-r--r-- | src/sys/event.rs | 25 | ||||
-rw-r--r-- | src/sys/ptrace/linux.rs | 18 | ||||
-rw-r--r-- | src/sys/signal.rs | 77 | ||||
-rw-r--r-- | src/sys/termios.rs | 121 | ||||
-rw-r--r-- | test/sys/test_ptrace.rs | 42 |
8 files changed, 271 insertions, 159 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 5031d02c..3e2c9680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1473](https://github.com/nix-rust/nix/pull/1473)) - Added `setrlimit` and `getrlimit`. (#[1302](https://github.com/nix-rust/nix/pull/1302)) +- Added `ptrace::interrupt` method for platforms that support `PTRACE_INTERRUPT` + (#[1422](https://github.com/nix-rust/nix/pull/1422)) ### Changed @@ -43,14 +45,29 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Many more functions, mostly contructors, are now `const`. (#[1476](https://github.com/nix-rust/nix/pull/1476)) +- `sys::event::KEvent::filter` now returns a `Result` instead of being + infalliable. The only cases where it will now return an error are cases + where it previously would've had undefined behavior. + (#[1484](https://github.com/nix-rust/nix/pull/1484)) + ### Fixed - Added more errno definitions for better backwards compatibility with Nix 0.21.0. (#[1467](https://github.com/nix-rust/nix/pull/1467)) +- Fixed potential undefined behavior in `Signal::try_from` on some platforms. + (#[1484](https://github.com/nix-rust/nix/pull/1484)) + ### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) +- Removed `nix::sys::signal::NSIG`. It was of dubious utility, and not correct + for all platforms. + (#[1484](https://github.com/nix-rust/nix/pull/1484)) + ## [0.22.0] - 9 July 2021 ### Added - Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445)) @@ -25,7 +25,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "9c1489fa8", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "f5e31f208", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" diff --git a/src/macros.rs b/src/macros.rs index 7d6ac8df..927e7e7c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -83,9 +83,9 @@ macro_rules! libc_bitflags { macro_rules! libc_enum { // Exit rule. (@make_enum + name: $BitFlags:ident, { $v:vis - name: $BitFlags:ident, attrs: [$($attrs:tt)*], entries: [$($entries:tt)*], } @@ -97,38 +97,98 @@ macro_rules! libc_enum { } }; + // Exit rule including TryFrom + (@make_enum + name: $BitFlags:ident, + { + $v:vis + attrs: [$($attrs:tt)*], + entries: [$($entries:tt)*], + from_type: $repr:path, + try_froms: [$($try_froms:tt)*] + } + ) => { + $($attrs)* + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + $v enum $BitFlags { + $($entries)* + } + #[allow(unused_doc_comment)] + impl ::std::convert::TryFrom<$repr> for $BitFlags { + type Error = $crate::Error; + fn try_from(x: $repr) -> $crate::Result<Self> { + match x { + $($try_froms)* + _ => Err($crate::Error::EINVAL) + } + } + } + }; + // Done accumulating. (@accumulate_entries + name: $BitFlags:ident, + { + $v:vis + attrs: $attrs:tt, + }, + $entries:tt, + $try_froms:tt; + ) => { + libc_enum! { + @make_enum + name: $BitFlags, + { + $v + attrs: $attrs, + entries: $entries, + } + } + }; + + // Done accumulating and want TryFrom + (@accumulate_entries + name: $BitFlags:ident, { $v:vis - name: $BitFlags:ident, attrs: $attrs:tt, + from_type: $repr:path, }, - $entries:tt; + $entries:tt, + $try_froms:tt; ) => { libc_enum! { @make_enum + name: $BitFlags, { $v - name: $BitFlags, attrs: $attrs, entries: $entries, + from_type: $repr, + try_froms: $try_froms } } }; // Munch an attr. (@accumulate_entries + name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*]; + [$($entries:tt)*], + [$($try_froms:tt)*]; #[$attr:meta] $($tail:tt)* ) => { libc_enum! { @accumulate_entries + name: $BitFlags, $prefix, [ $($entries)* #[$attr] + ], + [ + $($try_froms)* + #[$attr] ]; $($tail)* } @@ -136,32 +196,47 @@ macro_rules! libc_enum { // Munch last ident if not followed by a comma. (@accumulate_entries + name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*]; + [$($entries:tt)*], + [$($try_froms:tt)*]; $entry:ident ) => { libc_enum! { @accumulate_entries + name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry, + ], + [ + $($try_froms)* + libc::$entry => Ok($BitFlags::$entry), ]; } }; // Munch an ident; covers terminating comma case. (@accumulate_entries + name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*]; - $entry:ident, $($tail:tt)* + [$($entries:tt)*], + [$($try_froms:tt)*]; + $entry:ident, + $($tail:tt)* ) => { libc_enum! { @accumulate_entries + name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry, + ], + [ + $($try_froms)* + libc::$entry => Ok($BitFlags::$entry), ]; $($tail)* } @@ -169,16 +244,24 @@ macro_rules! libc_enum { // Munch an ident and cast it to the given type; covers terminating comma. (@accumulate_entries + name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*]; - $entry:ident as $ty:ty, $($tail:tt)* + [$($entries:tt)*], + [$($try_froms:tt)*]; + $entry:ident as $ty:ty, + $($tail:tt)* ) => { libc_enum! { @accumulate_entries + name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry as $ty, + ], + [ + $($try_froms)* + libc::$entry as $ty => Ok($BitFlags::$entry), ]; $($tail)* } @@ -193,11 +276,34 @@ macro_rules! libc_enum { ) => { libc_enum! { @accumulate_entries + name: $BitFlags, + { + $v + attrs: [$(#[$attr])*], + }, + [], + []; + $($vals)* + } + }; + + // Entry rule including TryFrom + ( + $(#[$attr:meta])* + $v:vis enum $BitFlags:ident { + $($vals:tt)* + } + impl TryFrom<$repr:path> + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, { $v - name: $BitFlags, attrs: [$(#[$attr])*], + from_type: $repr, }, + [], []; $($vals)* } diff --git a/src/sys/event.rs b/src/sys/event.rs index 1f4c1b41..c648f5eb 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -6,9 +6,9 @@ use crate::{Errno, Result}; use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t}; #[cfg(target_os = "netbsd")] use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t}; +use std::convert::TryInto; use std::os::unix::io::RawFd; use std::ptr; -use std::mem; // Redefine kevent in terms of programmer-friendly enums and bitfields. #[repr(C)] @@ -76,6 +76,7 @@ libc_enum! { EVFILT_VNODE, EVFILT_WRITE, } + impl TryFrom<type_of_event_filter> } #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -233,8 +234,8 @@ impl KEvent { self.kevent.ident } - pub fn filter(&self) -> EventFilter { - unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) } + pub fn filter(&self) -> Result<EventFilter> { + self.kevent.filter.try_into() } pub fn flags(&self) -> EventFlag { @@ -313,6 +314,8 @@ pub fn ev_set(ev: &mut KEvent, #[test] fn test_struct_kevent() { + use std::mem; + let udata : intptr_t = 12345; let actual = KEvent::new(0xdead_beef, @@ -322,10 +325,24 @@ fn test_struct_kevent() { 0x1337, udata); assert_eq!(0xdead_beef, actual.ident()); - assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter); + let filter = actual.kevent.filter; + assert_eq!(libc::EVFILT_READ, filter); assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); assert_eq!(0x1337, actual.data() as type_of_data); assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>()); } + +#[test] +fn test_kevent_filter() { + let udata : intptr_t = 12345; + + let actual = KEvent::new(0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + 0x1337, + udata); + assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); +} 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/src/sys/signal.rs b/src/sys/signal.rs index 0911cfaa..e68ebf16 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -6,7 +6,6 @@ use crate::{Error, Result}; use crate::errno::Errno; use crate::unistd::Pid; -use std::convert::TryFrom; use std::mem; use std::fmt; use std::str::FromStr; @@ -71,6 +70,7 @@ libc_enum!{ target_os = "redox")))] SIGINFO, } + impl TryFrom<i32> } impl FromStr for Signal { @@ -335,8 +335,6 @@ const SIGNALS: [Signal; 31] = [ SIGEMT, SIGINFO]; -pub const NSIG: libc::c_int = 32; - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct SignalIterator { next: usize, @@ -362,18 +360,6 @@ impl Signal { } } -impl TryFrom<libc::c_int> for Signal { - type Error = Error; - - fn try_from(signum: libc::c_int) -> Result<Signal> { - if 0 < signum && signum < NSIG { - Ok(unsafe { mem::transmute(signum) }) - } else { - Err(Error::from(Errno::EINVAL)) - } - } -} - pub const SIGIOT : Signal = SIGABRT; pub const SIGPOLL : Signal = SIGIO; pub const SIGUNUSED : Signal = SIGSYS; @@ -489,6 +475,8 @@ impl SigSet { /// signal mask becomes pending, and returns the accepted signal. #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait pub fn wait(&self) -> Result<Signal> { + use std::convert::TryFrom; + let mut signum = mem::MaybeUninit::uninit(); let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) }; @@ -584,9 +572,31 @@ impl SigAction { match self.sigaction.sa_sigaction { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, - f if self.flags().contains(SaFlags::SA_SIGINFO) => - SigHandler::SigAction( unsafe { mem::transmute(f) } ), - f => SigHandler::Handler( unsafe { mem::transmute(f) } ), + p if self.flags().contains(SaFlags::SA_SIGINFO) => + SigHandler::SigAction( + // Safe for one of two reasons: + // * The SigHandler was created by SigHandler::new, in which + // case the pointer is correct, or + // * The SigHandler was created by signal or sigaction, which + // are unsafe functions, so the caller should've somehow + // ensured that it is correctly initialized. + unsafe{ + *(&p as *const usize + as *const extern fn(_, _, _)) + } + as extern fn(_, _, _)), + p => SigHandler::Handler( + // Safe for one of two reasons: + // * The SigHandler was created by SigHandler::new, in which + // case the pointer is correct, or + // * The SigHandler was created by signal or sigaction, which + // are unsafe functions, so the caller should've somehow + // ensured that it is correctly initialized. + unsafe{ + *(&p as *const usize + as *const extern fn(libc::c_int)) + } + as extern fn(libc::c_int)), } } @@ -596,7 +606,18 @@ impl SigAction { match self.sigaction.sa_handler { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, - f => SigHandler::Handler( unsafe { mem::transmute(f) } ), + p => SigHandler::Handler( + // Safe for one of two reasons: + // * The SigHandler was created by SigHandler::new, in which + // case the pointer is correct, or + // * The SigHandler was created by signal or sigaction, which + // are unsafe functions, so the caller should've somehow + // ensured that it is correctly initialized. + unsafe{ + *(&p as *const usize + as *const extern fn(libc::c_int)) + } + as extern fn(libc::c_int)), } } } @@ -608,9 +629,16 @@ impl SigAction { /// /// # Safety /// -/// Signal handlers may be called at any point during execution, which limits what is safe to do in -/// the body of the signal-catching function. Be certain to only make syscalls that are explicitly -/// marked safe for signal handlers and only share global data using atomics. +/// * Signal handlers may be called at any point during execution, which limits +/// what is safe to do in the body of the signal-catching function. Be certain +/// to only make syscalls that are explicitly marked safe for signal handlers +/// and only share global data using atomics. +/// +/// * There is also no guarantee that the old signal handler was installed +/// correctly. If it was installed by this crate, it will be. But if it was +/// installed by, for example, C code, then there is no guarantee its function +/// pointer is valid. In that case, this function effectively dereferences a +/// raw pointer of unknown provenance. pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit(); @@ -689,7 +717,10 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> match oldhandler { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, - f => SigHandler::Handler(mem::transmute(f)), + p => SigHandler::Handler( + *(&p as *const usize + as *const extern fn(libc::c_int)) + as extern fn(libc::c_int)), } }) } diff --git a/src/sys/termios.rs b/src/sys/termios.rs index b29d3b98..01d46080 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -152,11 +152,11 @@ //! # } //! ``` use cfg_if::cfg_if; -use crate::{Error, Result}; +use crate::Result; use crate::errno::Errno; use libc::{self, c_int, tcflag_t}; use std::cell::{Ref, RefCell}; -use std::convert::{From, TryFrom}; +use std::convert::From; use std::mem; use std::os::unix::io::RawFd; @@ -340,119 +340,7 @@ libc_enum!{ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] B4000000, } -} - -impl TryFrom<libc::speed_t> for BaudRate { - type Error = Error; - - fn try_from(s: libc::speed_t) -> Result<BaudRate> { - use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, - B9600, B19200, B38400, B57600, B115200, B230400}; - #[cfg(any(target_os = "android", target_os = "linux"))] - use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000}; - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - use libc::{B2500000, B3000000, B3500000, B4000000}; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - use libc::{B7200, B14400, B28800, B76800}; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd"))] - use libc::{B460800, B921600}; - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - use libc::{B153600, B307200, B460800, B921600}; - - match s { - B0 => Ok(BaudRate::B0), - B50 => Ok(BaudRate::B50), - B75 => Ok(BaudRate::B75), - B110 => Ok(BaudRate::B110), - B134 => Ok(BaudRate::B134), - B150 => Ok(BaudRate::B150), - B200 => Ok(BaudRate::B200), - B300 => Ok(BaudRate::B300), - B600 => Ok(BaudRate::B600), - B1200 => Ok(BaudRate::B1200), - B1800 => Ok(BaudRate::B1800), - B2400 => Ok(BaudRate::B2400), - B4800 => Ok(BaudRate::B4800), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - B7200 => Ok(BaudRate::B7200), - B9600 => Ok(BaudRate::B9600), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - B14400 => Ok(BaudRate::B14400), - B19200 => Ok(BaudRate::B19200), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - B28800 => Ok(BaudRate::B28800), - B38400 => Ok(BaudRate::B38400), - B57600 => Ok(BaudRate::B57600), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - B76800 => Ok(BaudRate::B76800), - B115200 => Ok(BaudRate::B115200), - #[cfg(any(target_os = "illumos", - target_os = "solaris"))] - B153600 => Ok(BaudRate::B153600), - B230400 => Ok(BaudRate::B230400), - #[cfg(any(target_os = "illumos", - target_os = "solaris"))] - B307200 => Ok(BaudRate::B307200), - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - B460800 => Ok(BaudRate::B460800), - #[cfg(any(target_os = "android", target_os = "linux"))] - B500000 => Ok(BaudRate::B500000), - #[cfg(any(target_os = "android", target_os = "linux"))] - B576000 => Ok(BaudRate::B576000), - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - B921600 => Ok(BaudRate::B921600), - #[cfg(any(target_os = "android", target_os = "linux"))] - B1000000 => Ok(BaudRate::B1000000), - #[cfg(any(target_os = "android", target_os = "linux"))] - B1152000 => Ok(BaudRate::B1152000), - #[cfg(any(target_os = "android", target_os = "linux"))] - B1500000 => Ok(BaudRate::B1500000), - #[cfg(any(target_os = "android", target_os = "linux"))] - B2000000 => Ok(BaudRate::B2000000), - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - B2500000 => Ok(BaudRate::B2500000), - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - B3000000 => Ok(BaudRate::B3000000), - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - B3500000 => Ok(BaudRate::B3500000), - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - B4000000 => Ok(BaudRate::B4000000), - _ => Err(Error::from(Errno::EINVAL)) - } - } + impl TryFrom<libc::speed_t> } #[cfg(any(target_os = "freebsd", @@ -604,7 +492,9 @@ libc_bitflags! { ICRNL; IXON; IXOFF; + #[cfg(not(target_os = "redox"))] IXANY; + #[cfg(not(target_os = "redox"))] IMAXBEL; #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] IUTF8; @@ -1116,6 +1006,7 @@ pub fn tcgetsid(fd: RawFd) -> Result<Pid> { #[cfg(test)] mod test { use super::*; + use std::convert::TryFrom; #[test] fn try_from() { 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", |