Skip to content

Safe Library::new() can call any unsafe global constructors #86

@ghost

Description

This is unsound. It should be an unsafe function instead.

For example, this on x86_64-unknown-linux-gnu:

Cargo.toml:

[workspace]
members = ["evil", "loader"]

evil/Cargo.toml:

[package]
name = "evil"
version = "0.0.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]

evil/src/lib.rs:

unsafe extern "C" fn evil() -> ! {
    std::hint::unreachable_unchecked()
}

#[link_section = ".init_array"]
#[used]
static EVIL: unsafe extern "C" fn() -> ! = evil;

loader/Cargo.toml:

[package]
name = "loader"
version = "0.0.0"
edition = "2018"

[dependencies]
libloading.git = "https://github.com/nagisa/rust_libloading.git"

loader/src/main.rs:

#![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();
}

Triggers SIGILL (in debug mode) because std::hint::unreachable_unchecked() is called.

Backtrace
#0  core::hint::unreachable_unchecked ()
#1  0x00007ffff7fc2119 in evil::evil ()
#2  0x00007ffff7fe0b8a in ?? () from /lib64/ld-linux-x86-64.so.2
#3  0x00007ffff7fe0c91 in ?? () from /lib64/ld-linux-x86-64.so.2
#4  0x00007ffff7edb915 in __GI__dl_catch_exception (exception=<optimized out>, operate=<optimized out>, args=<optimized out>)
#5  0x00007ffff7fe50bf in ?? () from /lib64/ld-linux-x86-64.so.2
#6  0x00007ffff7edb8b8 in __GI__dl_catch_exception (exception=<optimized out>, operate=<optimized out>, args=<optimized out>)
#7  0x00007ffff7fe45fa in ?? () from /lib64/ld-linux-x86-64.so.2
#8  0x00007ffff7fa934c in dlopen_doit (a=a@entry=0x7fffffffd380)
#9  0x00007ffff7edb8b8 in __GI__dl_catch_exception (exception=exception@entry=0x7fffffffd320, operate=<optimized out>, args=<optimized out>)
#10 0x00007ffff7edb983 in __GI__dl_catch_error (objname=0x5555555a3ca0, errstring=0x5555555a3ca8, mallocedp=0x5555555a3c98, operate=<optimized out>, args=<optimized out>)
#11 0x00007ffff7fa9b59 in _dlerror_run (operate=operate@entry=0x7ffff7fa92f0 <dlopen_doit>, args=args@entry=0x7fffffffd380)
#12 0x00007ffff7fa93da in __dlopen (file=<optimized out>, mode=<optimized out>)
#13 0x000055555555a7f4 in libloading::os::unix::Library::open::{{closure}} ()
#14 0x000055555555a276 in libloading::os::unix::with_dlerror (
    wrap=0x55555555b2a0 <core::ops::function::FnOnce::call_once>, closure=...)
#15 0x000055555555a64f in libloading::os::unix::Library::open (filename=..., flags=2)
#16 0x000055555555a402 in libloading::os::unix::Library::new (filename=...)
#17 0x000055555555b52c in libloading::Library::new (filename=...)
#18 0x000055555555b618 in loader::main ()

Similarly, Library::new() calls the unsafe DllMain() on Windows.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions