@Michael-F-Bryan in this group, recommended that I use cdylib as crate type to build an Rust LD_PRELOAD shared library I am working with. I was using dylib before that.
My reading of other threads i this group also backsup his recommendation
Interestingly enough dylib was working for me. I then switched cdylib and the LD_PRELOAD intercept portion stopped working. Though the .so still gets exectued as shown below.
Here is an example rust shared library code I used for testing. It intercepts readlink to print some debug print messages and continues to the original readlink.
extern crate core;
extern crate libc;
#[macro_use]
extern crate ctor;
use libc::{c_void,c_char,c_int,size_t,ssize_t};
use std::sync::atomic;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub mod dyld_insert_libraries;
/* Some Rust library functionality (e.g., jemalloc) initializes
* lazily, after the hooking library has inserted itself into the call
* path. If the initialization uses any hooked functions, this will lead
* to an infinite loop. Work around this by running some initialization
* code in a static constructor, and bypassing all hooks until it has
* completed. */
static INIT_STATE: atomic::AtomicBool = atomic::AtomicBool::new(false);
pub fn initialized() -> bool {
INIT_STATE.load(atomic::Ordering::SeqCst)
}
#[ctor]
fn initialize() {
Box::new(0u8);
INIT_STATE.store(true, atomic::Ordering::SeqCst);
println!("Constructor");
}
#[link(name = "dl")]
extern "C" {
fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}
const RTLD_NEXT: *const c_void = -1isize as *const c_void;
pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
if ptr.is_null() {
panic!("redhook: Unable to find underlying function for {}", symbol);
}
ptr as *const u8
}
#[allow(non_camel_case_types)]
pub struct readlink {__private_field: ()}
#[allow(non_upper_case_globals)]
static readlink: readlink = readlink {__private_field: ()};
impl readlink {
fn get(&self) -> unsafe extern fn (path: *const c_char, buf: *mut c_char, bufsiz: size_t) -> ssize_t {
use ::std::sync::Once;
static mut REAL: *const u8 = 0 as *const u8;
static mut ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
REAL = dlsym_next(concat!("readlink", "\0"));
});
::std::mem::transmute(REAL)
}
}
#[no_mangle]
pub unsafe extern "C" fn readlink(path: *const c_char, buf: *mut c_char, bufsiz: size_t) -> ssize_t {
println!("readlink");
if initialized() {
println!("initialized");
::std::panic::catch_unwind(|| my_readlink ( path, buf, bufsiz )).ok()
} else {
println!("not initialized");
None
}.unwrap_or_else(|| readlink.get() ( path, buf, bufsiz ))
}
}
pub unsafe fn my_readlink(path: *const c_char, buf: *mut c_char, bufsiz: size_t) -> ssize_t {
println!("my_readlink");
readlink.get()(path, buf, bufsiz)
}
My Cargo.toml looks like this
[package]
name = "readlink"
version = "0.1.0"
authors = ["Saravanan Shanmugham <sarvi@cisco.com>"]
[lib]
name = "readlink"
crate_type = ["dylib"]
[dependencies]
libc = "0.2"
ctor = "0.1.15"
And this works. I see the constructor executing, and my_readlink which is my itnercept function and ls -al /tmp/link works and shows the symlink as expected, so the original readlink was executed as well. So all is well here
bash-4.4$ LD_PRELOAD=target/debug/libreadlink.so ls -al /tmp/link
Constructor
readlink
initialized
my_readlink
lrwxrwxrwx 1 sarvi eng 9 Aug 31 11:11 /tmp/link -> /tmp/file
bash-4.4$
I then changed
crate_type = ["dylib"]
to
crate_type = ["cdylib"]
And I see this. Only the constructor of libreadlink.so gets executed. But none of the interception happens.
bash-4.4$ LD_PRELOAD=target/debug/libreadlink.so ls -al /tmp/link
Constructor
lrwxrwxrwx 1 sarvi eng 9 Aug 31 11:11 /tmp/link -> /tmp/file
bash-4.4$
Is cdylib the right choice? and why doesnt my interception not work as the recommended cdylib but works as a dylib ?
Considering dylib is supposed to be smaller and is working. Can I continue as dylib? Or should I be worried about any other pitfalls for dylibs exposing C externs for calls from other C programs?