Problem overriding libc functions with LD_PRELOAD

I want to override the fopen function in libc so that for example I can print something before the main functionality. Consider this code:

use libc::FILE;
use libc::c_char;
use libc::fopen as fopen_c;

#[no_mangle]
#[link(name="fopen")]
unsafe fn fopen(filename: *const c_char, mode: *const c_char) {
    println!("made some change");
}

if I Use LD_PRELOAD and run a c file that uses fopen , the result of fopen would not be a returned file, but the printed string. But what if I want to keep the main functionality of it, and also print the string ?
something like this:

use libc::fopen as fopen_c;
unsafe fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
    println!("made some chnge");
    fopen_c(filename, mode)
}

Running the code above will result in an infinite recursion.

Any idea how can I fix it ?

You probably need something like dlsym to get the original fopen.

1 Like

Can you explain a little bit more ?

http://samanbarghi.com/blog/2014/09/05/how-to-wrap-a-system-call-libc-function-in-linux/

This might help you :slight_smile:

If you need some further help, here's an quick puts example:

use libc::c_char;
use std::ffi::CString;

#[no_mangle]
unsafe extern "C" fn puts(s: *const c_char) -> libc::c_int {
    println!("made some chnge");

    let puts_ptr = libc::dlsym(libc::RTLD_NEXT, CString::new("puts").unwrap().into_raw());
    let real_puts: fn(*const c_char) -> libc::c_int = std::mem::transmute(puts_ptr);
    real_puts(s)
}

Note, this is an example. Make sure to make null checks and stuff...

1 Like

Also make sure to use extern "C". These functions need to use the C ABI, not the Rust ABI.

And you probably don't want #[link(name = "puts")]. Either use #[no_mangle] or #[export_name = "puts"].

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.