Skip to content

Commit be54114

Browse files
committed
Add test for ptrace_set_syscall_info
1 parent 1f0469c commit be54114

File tree

1 file changed

+70
-2
lines changed

1 file changed

+70
-2
lines changed

test/sys/test_ptrace.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ use nix::unistd::getpid;
1313
#[cfg(linux_android)]
1414
use std::mem;
1515

16-
use crate::*;
17-
1816
#[test]
1917
fn test_ptrace() {
2018
// Just make sure ptrace can be called at all, for now.
@@ -410,3 +408,73 @@ fn test_ptrace_syscall_info() {
410408
},
411409
}
412410
}
411+
412+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
413+
#[test]
414+
fn test_ptrace_set_syscall_info() {
415+
use nix::sys::mman::{mmap_anonymous, MapFlags, ProtFlags};
416+
use nix::sys::ptrace;
417+
use nix::sys::signal::{raise, Signal::*};
418+
use nix::sys::wait::{waitpid, WaitStatus};
419+
use nix::unistd::{fork, ForkResult::*};
420+
use std::num::NonZero;
421+
422+
require_capability!("test_ptrace_set_syscall_info", CAP_SYS_PTRACE);
423+
424+
let _m = crate::FORK_MTX.lock();
425+
match unsafe { fork() }.expect("Error: Fork Failed") {
426+
Child => {
427+
ptrace::traceme().unwrap();
428+
raise(SIGSTOP).unwrap();
429+
430+
unsafe {
431+
let my_memory = mmap_anonymous(
432+
None,
433+
NonZero::new(1).unwrap(),
434+
ProtFlags::PROT_WRITE,
435+
MapFlags::MAP_PRIVATE,
436+
)
437+
.unwrap_or_else(|_| ::libc::_exit(1))
438+
.cast::<u8>();
439+
440+
*my_memory.as_ptr() = 42;
441+
::libc::_exit(0);
442+
}
443+
}
444+
Parent { child } => {
445+
assert_eq!(
446+
waitpid(child, None),
447+
Ok(WaitStatus::Stopped(child, SIGSTOP))
448+
);
449+
ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD).unwrap();
450+
ptrace::syscall(child, None).unwrap();
451+
452+
// Hijack the syscall and remove PROT_WRITE to force a SEGFAULT in the child
453+
assert_eq!(
454+
waitpid(child, None),
455+
Ok(WaitStatus::PtraceSyscall(child))
456+
);
457+
let mut si = ptrace::syscall_info(child).unwrap();
458+
assert_eq!(si.op, libc::PTRACE_SYSCALL_INFO_ENTRY);
459+
unsafe {
460+
si.u.entry.args[2] = ProtFlags::PROT_NONE.bits() as u64;
461+
}
462+
let set_syscall_res = ptrace::set_syscall_info(child, &si);
463+
ptrace::cont(child, None).unwrap();
464+
465+
if set_syscall_res.is_err() {
466+
assert_eq!(
467+
waitpid(child, None),
468+
Ok(WaitStatus::Exited(child, 0))
469+
);
470+
crate::skip!("PTRACE_SET_SYSCALL_INFO failed: Linux >= 6.16 is required, skipping test.");
471+
}
472+
473+
assert_eq!(
474+
waitpid(child, None),
475+
Ok(WaitStatus::Stopped(child, SIGSEGV))
476+
);
477+
ptrace::detach(child, SIGSEGV).unwrap();
478+
}
479+
}
480+
}

0 commit comments

Comments
 (0)