diff --git a/Cargo.toml b/Cargo.toml index 0281d57..a5cc432 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ chrono = "0.4.9" libc = "0.2.65" scopeguard = "1.0.0" url = "2.1.0" +once_cell = "1.7.2" [target.'cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] once_cell = "1.7.2" diff --git a/src/freedesktop.rs b/src/freedesktop.rs index 2cec491..25a7fed 100644 --- a/src/freedesktop.rs +++ b/src/freedesktop.rs @@ -627,8 +627,20 @@ struct MountPoint { #[cfg(target_os = "linux")] fn get_mount_points() -> Result, Error> { + use once_cell::sync::Lazy; use scopeguard::defer; use std::ffi::{CStr, CString}; + use std::sync::Mutex; + + // The getmntinfo() function writes the array of structures to an internal + // static object and returns a pointer to that object. Subsequent calls to + // getmntent() will modify the same object. This means that the function is + // not threadsafe. To help prevent multiple threads using it concurrently + // via get_mount_points a Mutex is used. + // We understand that threads can still call `libc::getmntent(…)` directly + // to bypass the lock and trigger UB. + static LOCK: Lazy> = Lazy::new(|| Mutex::new(())); + let _lock = LOCK.lock().unwrap(); //let file; let read_arg = CString::new("r").unwrap(); @@ -684,6 +696,8 @@ fn get_mount_points() -> Result, Error> { // getmntinfo() will modify the same object. This means that the function is // not threadsafe. To help prevent multiple threads using it concurrently // via get_mount_points a Mutex is used. + // We understand that threads can still call `libc::getmntinfo(…)` directly + // to bypass the lock and trigger UB. static LOCK: Lazy> = Lazy::new(|| Mutex::new(())); let _lock = LOCK.lock().unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 6d814b1..0f1f117 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,21 @@ //! Furthermore on Linux and on Windows additional functions are available from the `os_limited` //! module. //! +//! ### Potential UB on Linux and FreeBSD +//! +//! When querying information about mount points, non-threadsafe versions of `libc::getmnt(info|ent)` are +//! used which can cause UB if another thread calls into the same function, _probably_ only if the mountpoints +//! changed as well. +//! +//! To neutralize the issue, the respective function in this crate has been made thread-safe with a Mutex. +//! +//! **If your crate calls into the aforementioned methods directly or indirectly from other threads, +//! rather not use this crate.** +//! +//! As the handling of UB is clearly a trade-off and certainly goes against the zero-chance-of-UB goal +//! of the Rust community, please interact with us [in the tracking issue](https://github.com/Byron/trash-rs/issues/42) +//! to help find a more permanent solution. +//! //! ### Notes on the Linux implementation //! //! This library implements version 1.0 of the [Freedesktop.org