Skip to content

Commit 40ecada

Browse files
committed
Fix syscall_info
According to the man page: > The addr argument contains the size of the buffer pointed to by the > data argument (i.e., sizeof(struct ptrace_syscall_info)). We were setting the data argument, so this syscall was returning garbage. This is easily reproduced and verified by looking at the `op` value, which should range from 0 to 3. The PR associated with this commit contains a sample program to demonstrate this. The fix is done in the `ptrace_get_data` helper to avoid duplicating its implementation just for `syscall_info`. Of all the other callers, all but one are documented as ignoring `addr`. The other one (`PTRACE_GETREGS`) is documented as ignoring `addr` _except on SPARC systems_, on which `addr` and `data` are reversed. However, this is already not respected by `nix`, so this changes is not disruptive in this regard. There should be no performance concerns as we are replacing one constant with another.
1 parent a72936d commit 40ecada

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

changelog/2653.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed `nix::sys::ptrace::syscall_info`, which was not setting the `data` argument properly, causing garbage values to be returned.

examples/ptrace.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! Traces a child process using `ptrace`.
2+
//!
3+
//! The child issues a single `write` syscall, which is printed upon entry and exit.
4+
5+
#[cfg(target_os = "linux")]
6+
fn main() {
7+
let pid = unsafe { nix::unistd::fork().unwrap() };
8+
9+
match pid {
10+
nix::unistd::ForkResult::Child => {
11+
nix::sys::ptrace::traceme().unwrap();
12+
nix::sys::signal::raise(nix::sys::signal::Signal::SIGCONT).unwrap();
13+
println!("I'm issuing a syscall!");
14+
}
15+
nix::unistd::ForkResult::Parent { child } => {
16+
nix::sys::wait::waitpid(Some(child), None).unwrap();
17+
nix::sys::ptrace::setoptions(
18+
child,
19+
nix::sys::ptrace::Options::PTRACE_O_TRACESYSGOOD,
20+
)
21+
.unwrap();
22+
23+
nix::sys::ptrace::syscall(child, None).unwrap();
24+
nix::sys::wait::waitpid(Some(child), None).unwrap();
25+
let syscall_info = nix::sys::ptrace::syscall_info(child).unwrap();
26+
println!("{syscall_info:?}");
27+
assert!(syscall_info.op == libc::PTRACE_SYSCALL_INFO_ENTRY);
28+
29+
nix::sys::ptrace::syscall(child, None).unwrap();
30+
nix::sys::wait::waitpid(Some(child), None).unwrap();
31+
let syscall_info = nix::sys::ptrace::syscall_info(child).unwrap();
32+
println!("{syscall_info:?}");
33+
assert!(syscall_info.op == libc::PTRACE_SYSCALL_INFO_EXIT);
34+
}
35+
}
36+
}

src/sys/ptrace/linux.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
504504
libc::ptrace(
505505
request as RequestType,
506506
libc::pid_t::from(pid),
507-
ptr::null_mut::<T>(),
507+
std::mem::size_of::<T>(),
508508
data.as_mut_ptr(),
509509
)
510510
};

0 commit comments

Comments
 (0)