diff --git a/Cargo.toml b/Cargo.toml index 7d0854c..4987707 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,13 @@ features = [ "libloaderapi", ] +[target.'cfg(unix)'.dependencies.cfg-if] +version = "0.1" + +[dev-dependencies] +libc = "0.2" +static_assertions = "1.1" + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/src/changelog.rs b/src/changelog.rs index 2a94bcd..68c5b36 100644 --- a/src/changelog.rs +++ b/src/changelog.rs @@ -6,8 +6,9 @@ /// Release 0.6.3 (2020-08-22) /// /// * Improve documentation, allowing to view all of the os-specific functionality from -/// documentation generated for any target. -/// * Add [`os::windows::Library::this`]. +/// documentation generated for any target; +/// * Add [`os::windows::Library::this`]; +/// * Added constants to use with OS-specific `Library::open`. /// /// [`os::windows::Library::this`]: crate::os::windows::Library::this diff --git a/src/os/unix/consts.rs b/src/os/unix/consts.rs new file mode 100644 index 0000000..823155e --- /dev/null +++ b/src/os/unix/consts.rs @@ -0,0 +1,230 @@ +use std::os::raw::c_int; + +/// Perform lazy binding. +/// +/// Relocations shall be performed at an implementation-defined time, ranging from the time +/// of the [`Library::open`] call until the first reference to a given symbol occurs. +/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic +/// symbol binding since a process might not reference all of the symbols in an executable +/// object file. And, for systems supporting dynamic symbol resolution for normal process +/// execution, this behavior mimics the normal handling of process execution. +/// +/// Conflicts with [`RTLD_NOW`]. +/// +/// [`Library::open`]: crate::os::unix::Library::open +pub const RTLD_LAZY: c_int = posix::RTLD_LAZY; + +/// Perform eager binding. +/// +/// All necessary relocations shall be performed when the executable object file is first +/// loaded. This may waste some processing if relocations are performed for symbols +/// that are never referenced. This behavior may be useful for applications that need to +/// know that all symbols referenced during execution will be available before +/// [`Library::open`] returns. +/// +/// Conflicts with [`RTLD_LAZY`]. +/// +/// [`Library::open`]: crate::os::unix::Library::open +pub const RTLD_NOW: c_int = posix::RTLD_NOW; + +/// Make loaded symbols available for resolution globally. +/// +/// The executable object file's symbols shall be made available for relocation processing of any +/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from +/// [`Library::this`] allows executable object files loaded with this mode to be searched. +/// +/// [`Library::this`]: crate::os::unix::Library::this +/// [`Library::get`]: crate::os::unix::Library::get +pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL; + +/// Load symbols into an isolated namespace. +/// +/// The executable object file's symbols shall not be made available for relocation processing of +/// any other executable object file. This mode of operation is most appropriate for e.g. plugins. +pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL; + +#[cfg(docsrs)] +mod posix { + use super::c_int; + pub(super) const RTLD_LAZY: c_int = !0; + pub(super) const RTLD_NOW: c_int = !0; + pub(super) const RTLD_GLOBAL: c_int = !0; + pub(super) const RTLD_LOCAL: c_int = !0; +} + +#[cfg(not(docsrs))] +mod posix { + extern crate cfg_if; + use self::cfg_if::cfg_if; + use super::c_int; + cfg_if! { + if #[cfg(target_os = "haiku")] { + pub(super) const RTLD_LAZY: c_int = 0; + } else if #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_LAZY: c_int = 1; + } else { + compile_error!( + "Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(target_os = "haiku")] { + pub(super) const RTLD_NOW: c_int = 1; + } else if #[cfg(any( + target_os = "linux", + all(target_os = "android", target_pointer_width = "64"), + target_os = "emscripten", + + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_NOW: c_int = 2; + } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] { + pub(super) const RTLD_NOW: c_int = 0; + } else { + compile_error!( + "Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(any( + target_os = "haiku", + all(target_os = "android",target_pointer_width = "32"), + ))] { + pub(super) const RTLD_GLOBAL: c_int = 2; + } else if #[cfg(any( + target_env = "uclibc", + all(target_os = "linux", target_arch = "mips"), + all(target_os = "linux", target_arch = "mips64"), + ))] { + pub(super) const RTLD_GLOBAL: c_int = 4; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + ))] { + pub(super) const RTLD_GLOBAL: c_int = 8; + } else if #[cfg(any( + target_os = "linux", + all(target_os = "android", target_pointer_width = "64"), + target_os = "emscripten", + + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_GLOBAL: c_int = 0x100; + } else { + compile_error!( + "Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(target_os = "netbsd")] { + pub(super) const RTLD_LOCAL: c_int = 0x200; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + ))] { + pub(super) const RTLD_LOCAL: c_int = 4; + } else if #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + + target_os = "haiku", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_LOCAL: c_int = 0; + } else { + compile_error!( + "Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it." + ); + } + } +} + +// Other constants that exist but are not bound because they are platform-specific (non-posix) +// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls. +// +// RTLD_CONFGEN +// RTLD_DEFAULT +// RTLD_DI_CONFIGADDR +// RTLD_DI_LINKMAP +// RTLD_DI_LMID +// RTLD_DI_ORIGIN +// RTLD_DI_PROFILENAME +// RTLD_DI_PROFILEOUT +// RTLD_DI_SERINFO +// RTLD_DI_SERINFOSIZE +// RTLD_DI_TLS_DATA +// RTLD_DI_TLS_MODID +// RTLD_FIRST +// RTLD_GROUP +// RTLD_NEXT +// RTLD_PARENT +// RTLD_PROBE +// RTLD_SELF +// RTLD_WORLD +// RTLD_NODELETE +// RTLD_NOLOAD +// RTLD_DEEPBIND diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs index 41f871d..785c58f 100644 --- a/src/os/unix/mod.rs +++ b/src/os/unix/mod.rs @@ -3,7 +3,7 @@ #[cfg(all(docsrs, not(unix)))] mod unix_imports { } -#[cfg(unix)] +#[cfg(any(not(docsrs), unix))] mod unix_imports { pub(super) use std::os::unix::ffi::OsStrExt; } @@ -13,7 +13,9 @@ use util::{ensure_compatible_types, cstr_cow_from_bytes}; use std::ffi::{CStr, OsStr}; use std::{fmt, marker, mem, ptr}; use std::os::raw; +pub use self::consts::*; +mod consts; // dl* family of functions did not have enough thought put into it. // @@ -385,7 +387,6 @@ impl fmt::Debug for Symbol { } // Platform specific things - extern { fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void; fn dlclose(handle: *mut raw::c_void) -> raw::c_int; @@ -394,11 +395,6 @@ extern { fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int; } -#[cfg(not(target_os="android"))] -const RTLD_NOW: raw::c_int = 2; -#[cfg(target_os="android")] -const RTLD_NOW: raw::c_int = 0; - #[repr(C)] struct DlInfo { dli_fname: *const raw::c_char, diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 17f0ee4..c2e795a 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -3,11 +3,27 @@ #[cfg(all(docsrs, not(windows)))] mod windows_imports { pub(super) enum WORD {} - pub(super) enum DWORD {} + pub(super) struct DWORD; pub(super) enum HMODULE {} pub(super) enum FARPROC {} + + pub(super) mod consts { + use super::DWORD; + pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD; + pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD; + } } -#[cfg(windows)] +#[cfg(any(not(docsrs), windows))] mod windows_imports { extern crate winapi; pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC}; @@ -16,11 +32,27 @@ mod windows_imports { pub(super) use self::winapi::um::{errhandlingapi, libloaderapi}; pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt}; pub(super) const SEM_FAILCE: DWORD = 1; + + pub(super) mod consts { + pub(crate) use super::winapi::um::libloaderapi::{ + LOAD_IGNORE_CODE_AUTHZ_LEVEL, + LOAD_LIBRARY_AS_DATAFILE, + LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, + LOAD_LIBRARY_AS_IMAGE_RESOURCE, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, + LOAD_LIBRARY_SEARCH_SYSTEM32, + LOAD_LIBRARY_SEARCH_USER_DIRS, + LOAD_WITH_ALTERED_SEARCH_PATH, + LOAD_LIBRARY_REQUIRE_SIGNED_TARGET, + LOAD_LIBRARY_SAFE_CURRENT_DIRS, + }; + } } use self::windows_imports::*; use util::{ensure_compatible_types, cstr_cow_from_bytes}; - use std::ffi::{OsStr, OsString}; use std::{fmt, io, marker, mem, ptr}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -348,3 +380,115 @@ where F: FnOnce() -> Option { } }) } + +/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL. +/// +/// This action applies only to the DLL being loaded and not to its dependencies. This value is +/// recommended for use in setup programs that must run extracted DLLs during installation. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL; + +/// Map the file into the calling process’ virtual address space as if it were a data file. +/// +/// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call +/// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only +/// memory to raise an access violation. Use this flag when you want to load a DLL only to extract +/// messages or resources from it. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE; + +/// Map the file into the calling process’ virtual address space as if it were a data file. +/// +/// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive +/// write access for the calling process. Other processes cannot open the DLL file for write access +/// while it is in use. However, the DLL can still be opened by other processes. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE; + +/// Map the file into the process’ virtual address space as an image file. +/// +/// The loader does not load the static imports or perform the other usual initialization steps. +/// Use this flag when you want to load a DLL only to extract messages or resources from it. +/// +/// Unless the application depends on the file having the in-memory layout of an image, this value +/// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or +/// [`LOAD_LIBRARY_AS_DATAFILE`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE; + +/// Search application's installation directory for the DLL and its dependencies. +/// +/// Directories in the standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR; + +/// Search default directories when looking for the DLL and its dependencies. +/// +/// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`], +/// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the +/// standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; + +/// Directory that contains the DLL is temporarily added to the beginning of the list of +/// directories that are searched for the DLL’s dependencies. +/// +/// Directories in the standard search path are not searched. +/// +/// The `filename` parameter must specify a fully qualified path. This value cannot be combined +/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; + +/// Search `%windows%\system32` for the DLL and its dependencies. +/// +/// Directories in the standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32; + +/// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched +/// for the DLL and its dependencies. +/// +/// If more than one directory has been added, the order in which the directories are searched is +/// unspecified. Directories in the standard search path are not searched. This value cannot be +/// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS; + +/// If `filename specifies an absolute path, the system uses the alternate file search strategy +/// discussed in the [Remarks section] to find associated executable modules that the specified +/// module causes to be loaded. +/// +/// If this value is used and `filename` specifies a relative path, the behavior is undefined. +/// +/// If this value is not used, or if `filename` does not specify a path, the system uses the +/// standard search strategy discussed in the [Remarks section] to find associated executable +/// modules that the specified module causes to be loaded. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +/// +/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks +pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH; + +/// Specifies that the digital signature of the binary image must be checked at load time. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET; + +/// Allow loading a DLL for execution from the current directory only if it is under a directory in +/// the Safe load list. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS; diff --git a/tests/constants.rs b/tests/constants.rs new file mode 100644 index 0000000..ad910c4 --- /dev/null +++ b/tests/constants.rs @@ -0,0 +1,13 @@ +extern crate libloading; +extern crate libc; +extern crate static_assertions; + +#[cfg(all(test, unix))] +mod unix { + use super::static_assertions::const_assert_eq; + + const_assert_eq!(libloading::os::unix::RTLD_LOCAL, libc::RTLD_LOCAL); + const_assert_eq!(libloading::os::unix::RTLD_GLOBAL, libc::RTLD_GLOBAL); + const_assert_eq!(libloading::os::unix::RTLD_NOW, libc::RTLD_NOW); + const_assert_eq!(libloading::os::unix::RTLD_LAZY, libc::RTLD_LAZY); +}