Skip to content

Commit 6639c59

Browse files
Merge #1697
1697: Add ptrace::read_user and ptrace::write_user r=rtzoeller a=nbaksalyar Co-authored-by: Nikita Baksalyar <[email protected]>
2 parents 1647189 + c1c1c6c commit 6639c59

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1515
- Fixed compilation and updated support on Haiku
1616
- Added support for the `x86_64-unknown-haiku` target.
1717
(#[1703](https://github.com/nix-rust/nix/pull/1703))
18+
- Added `ptrace::read_user` and `ptrace::write_user` for Linux.
19+
(#[1697](https://github.com/nix-rust/nix/pull/1697))
1820

1921
### Changed
2022

src/sys/ptrace/linux.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,3 +481,24 @@ pub unsafe fn write(
481481
{
482482
ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
483483
}
484+
485+
/// Reads a word from a user area at `offset`.
486+
/// The user struct definition can be found in `/usr/include/sys/user.h`.
487+
pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> {
488+
ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut())
489+
}
490+
491+
/// Writes a word to a user area at `offset`.
492+
/// The user struct definition can be found in `/usr/include/sys/user.h`.
493+
///
494+
/// # Safety
495+
///
496+
/// The `data` argument is passed directly to `ptrace(2)`. Read that man page
497+
/// for guidance.
498+
pub unsafe fn write_user(
499+
pid: Pid,
500+
offset: AddressType,
501+
data: *mut c_void) -> Result<()>
502+
{
503+
ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop)
504+
}

test/sys/test_ptrace.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
#[cfg(all(target_os = "linux",
2+
any(target_arch = "x86_64",
3+
target_arch = "x86"),
4+
target_env = "gnu"))]
5+
use memoffset::offset_of;
16
use nix::errno::Errno;
27
use nix::unistd::getpid;
38
use nix::sys::ptrace;
@@ -197,15 +202,29 @@ fn test_ptrace_syscall() {
197202
#[cfg(target_arch = "x86")]
198203
let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
199204

205+
// this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`.
206+
#[cfg(target_arch = "x86_64")]
207+
let rax_offset = offset_of!(libc::user_regs_struct, orig_rax);
208+
#[cfg(target_arch = "x86")]
209+
let rax_offset = offset_of!(libc::user_regs_struct, orig_eax);
210+
211+
let get_syscall_from_user_area = || {
212+
// Find the offset of `user.regs.rax` (or `user.regs.eax` for x86)
213+
let rax_offset = offset_of!(libc::user, regs) + rax_offset;
214+
ptrace::read_user(child, rax_offset as _).unwrap() as libc::c_long
215+
};
216+
200217
// kill entry
201218
ptrace::syscall(child, None).unwrap();
202219
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
203220
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
221+
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);
204222

205223
// kill exit
206224
ptrace::syscall(child, None).unwrap();
207225
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
208226
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
227+
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);
209228

210229
// receive signal
211230
ptrace::syscall(child, None).unwrap();

0 commit comments

Comments
 (0)