2 releases
0.1.1 | May 28, 2023 |
---|---|
0.1.0 | May 27, 2023 |
#1626 in Rust patterns
21 downloads per month
7KB
54 lines
ld_preload_helpers
Rust macros to run code at load time and override C functions.
Mostly useful for LD_PRELOAD
hooks, hence the name.
Examples
C function overrides
Here open
is overridden to print something then forward to the real open
.
In the rare case that you should wish to recurse into the override, rather than
call the real API, use crate::open
. From anywhere else in the module, open
will refer to the override. To refer to the real function from elsewhere in
the program, use real_open
(as named at the declaration).
Multiple overrides may be specified within a single macro invocation and
multiple extern_c_overrides
invocations are supported if desired. This is
demonstrated below by an override of getuid
which adds 2000 to the user's id.
In std
mode (the default), panics in the override are caught and cause the catch
block to execute. In no_std
mode (not properly supported due to use of
OnceLock
; see below), there is no special panic
handling and the catch block is
ignored.
extern_c_overrides! {
unsafe fn open/real_open(pathname: *const c_char, flags: c_int, mode: libc::mode_t) -> c_int {
println!("RUST OPEN {:?} {:x} {:x}", unsafe { CStr::from_ptr(pathname) }, flags, mode);
// panic!("oops");
return open(pathname, flags, mode);
} catch {
errno::set_errno(errno::Errno(libc::ENODEV));
return -1;
}
unsafe fn getuid/real_getuid() -> libc::uid_t {
getuid() + 2000
} catch { u32::MAX }
}
Image load hook
Called whenever the program/library is loaded, prior to the main entry point
being run. Note this demonstrates calling the overridden getuid
and real
getuid
.
Currently there can be only one of these owing to a fixed name being used for the generated function. But this may be extended in future to allow the user to pass a name.
on_load! {{
println!("INIT LIB {} {}", unsafe { getuid() }, unsafe { real_getuid() });
}}
Example runs
$ LD_PRELOAD=target/debug/liboverride.so id
INIT LIB 2501 501
uid=2501 gid=501 euid=501
$ LD_PRELOAD=target/debug/liboverride.so wc Cargo.lock
INIT LIB 2501 501
RUST OPEN "Cargo.lock" 0 52c47940
820 1588 21572 Cargo.lock
Notes on no_std
usage
std::sync::OnceLock
is the only dependency onstd
. Should considerconquer_once
or similar crates to supportno_std
.- Could also disable the need for this in single thread code to allow
no_std
. - TODO: In
no_std
client code, the catch block is unused; consider not requiring/accepting it in that case.
Dependencies
~44KB