2 个版本
0.1.1 | 2023 年 5 月 28 日 |
---|---|
0.1.0 | 2023 年 5 月 27 日 |
#1492 in Rust 模式
每月 21 次下载
7KB
54 行
ld_preload_helpers
Rust 宏,用于在加载时运行代码并覆盖 C 函数。
主要用于 LD_PRELOAD
钩子,因此得名。
示例
C 函数覆盖
在这里,open
被覆盖以打印一些内容,然后转发到真实的 open
。在极少数需要递归到覆盖而不是调用真实 API 的情况下,使用 crate::open
。在模块中的任何其他地方,open
将指向覆盖。要引用程序中的真实函数,请使用 real_open
(如声明中所命名)。
单个宏调用中可以指定多个覆盖,并且如果需要,支持多个 extern_c_overrides
调用。以下示例展示了覆盖 getuid
并将用户的 ID 增加 2000。
在 std
模式(默认模式)中,覆盖中的 panic 被捕获并导致捕获块执行。在 no_std
模式(由于使用 OnceLock
而未得到良好支持;见下文),没有特殊的 panic
处理,并且捕获块被忽略。
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 }
}
图像加载钩子
在程序/库加载时调用,在运行主入口点之前。注意,这演示了调用覆盖的 getuid
和真实的 getuid
。
目前由于使用的生成函数具有固定名称,因此只能有一个此类钩子。但在未来可能会扩展以允许用户传递名称。
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
使用说明
std::sync::OnceLock
是对std
的唯一依赖。应考虑使用conquer_once
或类似 crate 来支持no_std
。- 还可以在单线程代码中禁用此依赖,以允许使用
no_std
。 - 待办事项:在
no_std
客户端代码中,捕获块未使用;考虑在该情况下不要求/接受它。
依赖项
~43KB