Skip to content

Commit

Permalink
Add ptrace::read_user and ptrace::write_user
Browse files Browse the repository at this point in the history
  • Loading branch information
nbaksalyar committed May 15, 2022
1 parent 1647189 commit c1c1c6c
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- Fixed compilation and updated support on Haiku
- Added support for the `x86_64-unknown-haiku` target.
(#[1703](https://github.com/nix-rust/nix/pull/1703))
- Added `ptrace::read_user` and `ptrace::write_user` for Linux.
(#[1697](https://github.com/nix-rust/nix/pull/1697))

### Changed

Expand Down
21 changes: 21 additions & 0 deletions src/sys/ptrace/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,3 +481,24 @@ pub unsafe fn write(
{
ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
}

/// Reads a word from a user area at `offset`.
/// The user struct definition can be found in `/usr/include/sys/user.h`.
pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> {
ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut())
}

/// Writes a word to a user area at `offset`.
/// The user struct definition can be found in `/usr/include/sys/user.h`.
///
/// # Safety
///
/// The `data` argument is passed directly to `ptrace(2)`. Read that man page
/// for guidance.
pub unsafe fn write_user(
pid: Pid,
offset: AddressType,
data: *mut c_void) -> Result<()>
{
ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop)
}
19 changes: 19 additions & 0 deletions test/sys/test_ptrace.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[cfg(all(target_os = "linux",
any(target_arch = "x86_64",
target_arch = "x86"),
target_env = "gnu"))]
use memoffset::offset_of;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;
Expand Down Expand Up @@ -197,15 +202,29 @@ fn test_ptrace_syscall() {
#[cfg(target_arch = "x86")]
let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;

// this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`.
#[cfg(target_arch = "x86_64")]
let rax_offset = offset_of!(libc::user_regs_struct, orig_rax);
#[cfg(target_arch = "x86")]
let rax_offset = offset_of!(libc::user_regs_struct, orig_eax);

let get_syscall_from_user_area = || {
// Find the offset of `user.regs.rax` (or `user.regs.eax` for x86)
let rax_offset = offset_of!(libc::user, regs) + rax_offset;
ptrace::read_user(child, rax_offset as _).unwrap() as libc::c_long
};

// kill entry
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);

// kill exit
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);

// receive signal
ptrace::syscall(child, None).unwrap();
Expand Down

0 comments on commit c1c1c6c

Please sign in to comment.