Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix inconsistent reg struct layout for 64bit tracer and 32bit tracee #2448

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/2448.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Module sys/ptrace changes `ptrace::getregs` for x86_64/x86 to be unsafe function.
15 changes: 13 additions & 2 deletions src/sys/ptrace/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,17 @@ fn ptrace_peek(
}
}

/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`. Call `getregset` for safe version
///
/// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
/// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
/// on aarch64 and riscv64.
///
/// # Safety
///
/// Currently, in x86_64 platform, if the tracer is 64bit and tracee is 32bit, the return value is
/// undefined.
///
Evian-Zhang marked this conversation as resolved.
Show resolved Hide resolved
/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
#[cfg(all(
target_os = "linux",
Expand All @@ -321,7 +326,7 @@ fn ptrace_peek(
all(target_arch = "x86", target_env = "gnu")
)
))]
pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
pub unsafe fn getregs(pid: Pid) -> Result<user_regs_struct> {
ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
}

Expand All @@ -342,6 +347,9 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
}

/// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)`
///
/// Currently, in x86_64 platform, if the tracer is 64bit and tracee is 32bit, this function
/// will return EIO error.
#[cfg(all(
target_os = "linux",
target_env = "gnu",
Expand All @@ -367,6 +375,9 @@ pub fn getregset<S: RegisterSet>(pid: Pid) -> Result<S::Regs> {
(&mut iov as *mut libc::iovec).cast(),
)?;
};
if iov.iov_len != mem::size_of::<S::Regs>() {
return Err(Errno::EIO);
}
Ok(unsafe { data.assume_init() })
}

Expand Down
12 changes: 8 additions & 4 deletions test/sys/test_ptrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,16 @@ fn test_ptrace_syscall() {
.unwrap();

#[cfg(target_arch = "x86_64")]
let get_syscall_id =
|| ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
let get_syscall_id = || {
unsafe { ptrace::getregs(child) }.unwrap().orig_rax
as libc::c_long
};

#[cfg(target_arch = "x86")]
let get_syscall_id =
|| ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
let get_syscall_id = || {
unsafe { ptrace::getregs(child) }.unwrap().orig_eax
as libc::c_long
};

#[cfg(target_arch = "aarch64")]
let get_syscall_id =
Expand Down