Crates.io | ld_preload_helpers |
lib.rs | ld_preload_helpers |
version | 0.1.1 |
source | src |
created_at | 2023-05-27 15:42:49.696715 |
updated_at | 2023-05-28 22:35:03.794058 |
description | Macros to run code at load time and override C functions |
homepage | |
repository | https://github.com/abutcher-gh/ld_preload_helpers |
max_upload_size | |
id | 875985 |
size | 17,943 |
Rust macros to run code at load time and override C functions.
Mostly useful for LD_PRELOAD
hooks, hence the name.
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 }
}
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() });
}}
$ 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
no_std
usagestd::sync::OnceLock
is the only dependency on std
. Should consider conquer_once
or similar crates to support no_std
.no_std
.no_std
client code, the catch block is unused; consider not requiring/accepting it in that case.