mirror of
https://github.com/facebookexperimental/reverie.git
synced 2025-01-22 21:04:53 +00:00
Fix skip_seccomp_syscall
Summary: Fixes `skip_seccomp_syscall` on aarch64 to *actually* skip the syscall. I plan on cleaning this up a bit more in a later diff because we are calling `getregs` and `setregs` more than necessary on a per-interception basis. Reviewed By: VladimirMakaev Differential Revision: D40867423 fbshipit-source-id: d72b4998b5c1c44f426a9129eccb205ccfc320fa
This commit is contained in:
parent
0ae449caba
commit
90e39abc59
2 changed files with 31 additions and 5 deletions
|
@ -1485,16 +1485,24 @@ impl<L: Tool + 'static> TracedTask<L> {
|
|||
/// Set tracee state to Stopped/SIGTRP.
|
||||
/// Restore the registers to the state specified by the regs arg.
|
||||
async fn skip_seccomp_syscall(&mut self, task: Stopped) -> Result<Stopped, TraceError> {
|
||||
let regs = task.getregs()?;
|
||||
|
||||
// So here we are, at ptrace seccomp stop, if we simply resume, the kernel
|
||||
// would do the syscall, without our patch. we change to syscall number to
|
||||
// -1, so that kernel would simply skip the syscall, so that we can jump to
|
||||
// our patched syscall on the first run. Please note after calling this
|
||||
// function, the task state will no longer be in ptrace event seccomp.
|
||||
let mut new_regs = regs;
|
||||
*new_regs.orig_syscall_mut() = -1i64 as u64;
|
||||
task.setregs(new_regs)?;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let regs = task.getregs()?;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let mut new_regs = regs;
|
||||
*new_regs.orig_syscall_mut() = -1i64 as u64;
|
||||
task.setregs(new_regs)?;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
task.set_syscall(-1)?;
|
||||
|
||||
let mut running = task.step(None)?;
|
||||
|
||||
// After the step, wait for the next transition. Note that this can return
|
||||
|
@ -1503,6 +1511,7 @@ impl<L: Tool + 'static> TracedTask<L> {
|
|||
loop {
|
||||
match running.next_state().await? {
|
||||
Wait::Stopped(task, Event::Signal(Signal::SIGTRAP)) => {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
task.setregs(regs)?;
|
||||
break Ok(task);
|
||||
}
|
||||
|
|
|
@ -600,6 +600,23 @@ impl Stopped {
|
|||
Ok(Running::new(self.0))
|
||||
}
|
||||
|
||||
/// Sets the syscall to be executed. Only available on `aarch64`.
|
||||
///
|
||||
/// Normally, on x86_64, the register `orig_rax` should be set instead to
|
||||
/// modify the syscall number, which typically involves 3 ptrace calls:
|
||||
/// 1. getregs to get the current registers.
|
||||
/// 2. setregs to change `orig_rax` to set the syscall number.
|
||||
/// 3. setregs again to restore the original registers after the syscall
|
||||
/// has been executed.
|
||||
///
|
||||
/// `set_syscall` on `aarch64` has the advantage of only requiring a single
|
||||
/// ptrace call.
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn set_syscall(&self, nr: i32) -> Result<(), Error> {
|
||||
const NT_ARM_SYSTEM_CALL: i32 = 0x404;
|
||||
self.setregset(NT_ARM_SYSTEM_CALL, nr)
|
||||
}
|
||||
|
||||
/// Gets info about the signal that caused the process to be stopped.
|
||||
pub fn getsiginfo(&self) -> Result<libc::siginfo_t, Error> {
|
||||
ptrace::getsiginfo(self.0.into()).map_err(|err| self.map_nix_err(err))
|
||||
|
|
Loading…
Reference in a new issue