geofft / redhook

Dynamic function call interposition / hooking (LD_PRELOAD) for Rust
BSD 2-Clause "Simplified" License
177 stars 17 forks source link

feat: handle syscall #21

Open milahu opened 3 years ago

milahu commented 3 years ago

i want to intercept the statx call by node. problem is, instead of statx(...), node calls syscall(332, ...)

node/deps/uv/src/unix/linux-syscalls.c

#ifndef __NR_statx
# if defined(__x86_64__)
#  define __NR_statx 332
# elif defined(__i386__)
#  define __NR_statx 383

// ...

int uv__statx(int dirfd,
              const char* path,
              int flags,
              unsigned int mask,
              struct uv__statx* statxbuf) {
#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30
  return errno = ENOSYS, -1;
#else
  return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
#endif
}

currently i use this code to trap syscalls

extern crate libc;

#[macro_use]
extern crate redhook;

hook! {
    unsafe fn syscall(
        num: libc::c_long,
        a1: *mut libc::c_void,
        a2: *mut libc::c_void,
        a3: *mut libc::c_void,
        a4: *mut libc::c_void,
        a5: *mut libc::c_void
    ) -> libc::c_long => my_syscall {
        let retval = real!(syscall)(num, a1, a2, a3, a4, a5);
        if num == libc::SYS_statx {
            let dirfd = a1 as libc::c_int;
            let path = a2 as *const libc::c_char;
            let flags = a3 as libc::c_int;
            let mask = a4 as libc::c_uint;
            let statxbuf = a5 as *mut libc::statx;

            if let Ok(path) = std::str::from_utf8(std::ffi::CStr::from_ptr(path).to_bytes()) {
                println!("syscall(SYS_statx, {}) -> retval {:?}", path, retval);
            } else {
                println!("syscall(SYS_statx, ...) -> retval {:?}", retval);
            }
            println!("statx -> stx_mode {:?}", (*statxbuf).stx_mode);
        }
        return retval;
    }
}

maybe solve this with macros?

related: https://docs.rs/syscalls/0.4.2/syscalls/macro.syscall_args.html

milahu commented 3 years ago

related:

hook! {
    unsafe fn syscall(
        // ...
    ) -> libc::c_long => my_syscall {

        // ...
        let buf_len = real!(readlink)(path, buf, bufsiz);
        // error: readlink not found in this scope

        // this works
        let buf_len = real!(syscall)(
            libc::SYS_readlink,
            path as *mut libc::c_void,
            buf as *mut libc::c_void,
            bufsiz as *mut libc::c_void,
            std::ptr::null_mut() as *mut libc::c_void,
            std::ptr::null_mut() as *mut libc::c_void
        );

}

readlink is only available when i add

hook! {
    unsafe fn readlink(
        // ...
    ) -> ... => my_readlink {
        // ...
        real!(readlink)(path, buf, bufsiz);
}