summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Baksalyar <nikita.baksalyar@gmail.com>2022-04-14 01:05:30 +0100
committerNikita Baksalyar <nikita.baksalyar@gmail.com>2022-05-15 23:36:02 +0100
commitc1c1c6cfe41e597b745c4770c665b58a268cebc9 (patch)
tree970e43b2f23f6e54cbb62613be8aa03b774f01fc
parent16471898160b5b1fa27689a26727d1d82ddd5573 (diff)
downloadnix-c1c1c6cfe41e597b745c4770c665b58a268cebc9.zip
Add ptrace::read_user and ptrace::write_user
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/ptrace/linux.rs21
-rw-r--r--test/sys/test_ptrace.rs19
3 files changed, 42 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4cb9d2ae..59d25af0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
index 24152d7d..1d9b241c 100644
--- a/src/sys/ptrace/linux.rs
+++ b/src/sys/ptrace/linux.rs
@@ -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)
+}
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index 89c4e2dd..8556a548 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -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;
@@ -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();