-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safe Library::new()
can call any unsafe global constructors
#86
Comments
Thank you for the report. That's indeed a pretty nasty one! I think there are a number of tradeoffs and prior arts to consider here: Firstly, I believe the same kind of issue present when linking to a dynamic library through regular means ( On the other hand, the lack of This problem is significantly more interesting in the context of it being extremely easy to write a library that has unsound initializers in C++ or other such languages. I don't think there is much problem with making I wonder if there's anything in the way of requirements or invariants that the code calling # Safety
This call will execute initializers present in the loaded libraries.
These may be unsound and there's nothing you can do about it? And then the users trying to explain why the code they're calling is actually safe are forced to... let library = unsafe {
// SAFE: uh… lets just hope this solib does not have evil initializers?
Library::new("libpossiblyevil.so")
}; Welp. |
Indeed. However, in that case, the dynamic library is typically a build dependency, maybe (at least I hope) the user is more likely to acknowledge that it may be evil (just like they're statically linking an unsound Rust crate) or may be replaced with an evil one at runtime.
I think
But I think in most cases the user actually can't verify the type of the symbol. |
I went ahead and prepared a fix for #87. I will let it bake for a week and then release the new version the next weekend. (I also want to look into whether there might be things like… destructors. I know that they exist for TLS, but that is not strictly coupled to loading/unloading the library and could be attributed more to the TLS handling code instead) Thanks for the report! |
Not all destructors could be "attributed more to the TLS handling code":
extern "C" fn print() {
eprintln!("global destructor called");
}
#[link_section = ".fini_array"]
#[used]
static PRINT: extern "C" fn() = print;
#![forbid(unsafe_code)]
use libloading::Library;
fn main() {
let mut path = std::env::current_exe().unwrap();
assert!(path.pop());
path.push("libevil.so");
Library::new(path).unwrap();
eprintln!("library dropped");
} That prints:
Maybe they worth mentioning? |
Yeah, I suspected they'd exist, just didn't have the time to look into them. Thanks for bringing these up! For these there are two distinct options I guess: could make |
Deal with the fact that libloading::Library::new was declared unsafe in libloading 0.7; see nagisa/rust_libloading#86 and https://github.com/nagisa/rust_libloading/blob/0.8.3/src/changelog.rs#L96-L151 for details. Fixes rust-pcap#345.
* Update libloading from 0.6 to 0.8 Deal with the fact that libloading::Library::new was declared unsafe in libloading 0.7; see nagisa/rust_libloading#86 and https://github.com/nagisa/rust_libloading/blob/0.8.3/src/changelog.rs#L96-L151 for details. Fixes #345. * Update MSRV to 1.56 to support libloading 0.8.2 and later
This is unsound. It should be an unsafe function instead.
For example, this on
x86_64-unknown-linux-gnu
:Cargo.toml
:evil/Cargo.toml
:evil/src/lib.rs
:loader/Cargo.toml
:loader/src/main.rs
:Triggers SIGILL (in debug mode) because
std::hint::unreachable_unchecked()
is called.Backtrace
Similarly,
Library::new()
calls the unsafeDllMain()
on Windows.The text was updated successfully, but these errors were encountered: