-
Notifications
You must be signed in to change notification settings - Fork 17
Open
Description
git clone --depth=1 --branch=debug-noop-hooks https://github.com/milahu/nodejs-hide-symlinks
cd nodejs-hide-symlinks
cargo build
LD_PRELOAD=./target/debug/libnodejs_hide_symlinks.so readlink -f .
LD_PRELOAD=./target/debug/libnodejs_hide_symlinks.so coreutils --coreutils-prog=readlink -f .
LD_PRELOAD=./target/debug/libnodejs_hide_symlinks.so python -c "print(1)"
LD_PRELOAD=./target/debug/libnodejs_hide_symlinks.so bash -c "echo 1"
LD_PRELOAD fails on readlink -f .
LD_PRELOAD works with python -c "print(1)"
$ LD_PRELOAD=./target/debug/libnodejs_hide_symlinks.so python -c "print(1)"
keeping numeric syscall 186
hooking syscall readlink("/run/current-system/sw/bin/python", &buf, bufsz) -> retval: 69, buf: /nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/bin/python
hooking syscall readlink("/nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/bin/python", &buf, bufsz) -> retval: 10, buf: python3.12
hooking syscall readlink("/nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/bin/python3.12", &buf, bufsz) -> retval: -1, buf:
1
maybe blame stderr output buffering
see also: LD_PRELOAD does not work as expected
coreutils is *not* a setuid binary (access 4511/-r-s--x--x)
$ stat $(readlink -f $(which readlink)) | grep -e File -e Uid
File: /nix/store/vb8mdklw65p9wikp97ybmnyay0xzipx3-coreutils-9.5/bin/coreutils
Access: (0555/-r-xr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
$ stat $(readlink -f $(which mount)) | grep -e File -e Uid
File: /run/wrappers/wrappers.l8uO0XdEQ9/mount
Access: (4511/-r-s--x--x) Uid: ( 0/ root) Gid: ( 0/ root)
src/lib.rs
extern crate libc;
#[macro_use]
extern crate redhook;
use std::collections::HashMap;
use std::ffi::CString;
use std::env;
unsafe fn is_symlink(statxbuf: *const libc::statx) -> bool {
// https://man7.org/linux/man-pages/man7/inode.7.html
const S_IFMT: u16 = 0o170000; // bit mask for the file type bit field
const S_IFLNK: u16 = 0o120000; // symbolic link
return ((*statxbuf).stx_mode & S_IFMT) == S_IFLNK;
}
unsafe fn str_of_chars(cstr: *const libc::c_char) -> &'static str {
return std::str::from_utf8(std::ffi::CStr::from_ptr(cstr).to_bytes()).unwrap();
}
unsafe fn str_of_chars_len(cstr: *const libc::c_char, clen: libc::ssize_t) -> &'static str {
if clen < 0 {
return "";
}
return std::str::from_utf8(std::slice::from_raw_parts(cstr as *const u8, clen as usize)).unwrap();
}
unsafe fn string_of_statxbuf(statxbuf: *const libc::statx) -> String {
return format!("{{ stx_ino: {}, stx_mode: {:#o}, is_symlink: {:?} }}", (*statxbuf).stx_ino, (*statxbuf).stx_mode, is_symlink(statxbuf));
}
hook! {
// https://docs.rs/libc/latest/libc/fn.syscall.html
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 {
if num == libc::SYS_statx {
println!("hooking numeric syscall 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;
return statx_hooked(dirfd, path, flags, mask, statxbuf) as libc::c_long;
}
if num == libc::SYS_readlink {
println!("hooking numeric syscall readlink");
let path = a1 as *const libc::c_char;
let buf = a2 as *mut libc::c_char;
let bufsz = a3 as libc::size_t;
return readlink_hooked(path, buf, bufsz) as libc::c_long;
}
if num == libc::SYS_readlinkat {
println!("hooking numeric syscall readlinkat");
let dirfd = a1 as libc::c_int;
let pathname = a2 as *const libc::c_char;
let buf = a3 as *mut libc::c_char;
let bufsz = a4 as libc::size_t;
return readlinkat_hooked(dirfd, pathname, buf, bufsz) as libc::c_long;
}
if num == libc::SYS_open {
println!("hooking numeric syscall open");
let path = a1 as *const libc::c_char;
let oflag = a2 as libc::c_int;
return open_hooked(path, oflag) as libc::c_long;
}
if num == libc::SYS_openat {
println!("hooking numeric syscall openat");
let dirfd = a1 as libc::c_int;
let pathname = a2 as *const libc::c_char;
let flags = a3 as libc::c_int;
return openat_hooked(dirfd, pathname, flags) as libc::c_long;
}
println!("keeping numeric syscall {}", num);
return real!(syscall)(num, a1, a2, a3, a4, a5);
}
}
hook! {
unsafe fn statx(
dirfd: libc::c_int,
path: *const libc::c_char,
flags: libc::c_int,
mask: libc::c_uint,
statxbuf: *mut libc::statx // https://docs.rs/libc/0.2.103/libc/struct.statx.html
) -> libc::c_int => statx_hooked {
let mut retval = real!(statx)(dirfd, path, flags, mask, statxbuf);
eprintln!("nodejs-hide-symlinks statx({}, \"{}\", {}, {}, &statxbuf) -> retval: {:?}, statxbuf: {}", dirfd, str_of_chars(path), flags, mask, retval, string_of_statxbuf(statxbuf));
return retval;
}
}
hook! {
// https://docs.rs/libc/latest/libc/fn.readlink.html
unsafe fn readlink(
path: *const libc::c_char,
buf: *mut libc::c_char,
bufsz: libc::size_t
) -> libc::ssize_t => readlink_hooked {
let mut retval = real!(readlink)(path, buf, bufsz);
println!("hooking syscall readlink(\"{}\", &buf, bufsz) -> retval: {:?}, buf: {}", str_of_chars(path), retval, str_of_chars_len(buf, retval));
return retval;
}
}
hook! {
// https://docs.rs/libc/latest/libc/fn.readlinkat.html
unsafe fn readlinkat(
dirfd: libc::c_int,
pathname: *const libc::c_char,
buf: *mut libc::c_char,
bufsz: libc::size_t
) -> libc::ssize_t => readlinkat_hooked {
let mut retval = real!(readlinkat)(dirfd, pathname, buf, bufsz);
println!("hooking syscall readlinkat({}, \"{}\", &buf, bufsz) -> retval: {:?}, buf: {}", dirfd, str_of_chars(pathname), retval, str_of_chars_len(buf, retval));
return retval;
}
}
hook! {
// https://docs.rs/libc/latest/libc/fn.open.html
unsafe fn open(
path: *const libc::c_char,
oflag: libc::c_int
) -> libc::c_int => open_hooked {
let mut retval = real!(open)(path, oflag);
println!("hooking syscall open(\"{}\", {}) -> retval: {:?}", str_of_chars(path), oflag, retval);
return retval;
}
}
hook! {
// https://docs.rs/libc/latest/libc/fn.openat.html
unsafe fn openat(
dirfd: libc::c_int,
pathname: *const libc::c_char,
flags: libc::c_int
) -> libc::c_int => openat_hooked {
let mut retval = real!(openat)(dirfd, pathname, flags);
println!("hooking syscall openat({}, \"{}\", {}) -> retval: {:?}", dirfd, str_of_chars(pathname), flags, retval);
return retval;
}
}Metadata
Metadata
Assignees
Labels
No labels