Skip to content

Commit

Permalink
Add Mutex to linux version of get_mount_points(); document UB chance …
Browse files Browse the repository at this point in the history
…in lib.rs
  • Loading branch information
Byron committed Jan 23, 2022
1 parent 5c8e0ce commit c5c9c5e
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
14 changes: 14 additions & 0 deletions src/freedesktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,20 @@ struct MountPoint {

#[cfg(target_os = "linux")]
fn get_mount_points() -> Result<Vec<MountPoint>, 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<Mutex<()>> = Lazy::new(|| Mutex::new(()));
let _lock = LOCK.lock().unwrap();

//let file;
let read_arg = CString::new("r").unwrap();
Expand Down Expand Up @@ -684,6 +696,8 @@ fn get_mount_points() -> Result<Vec<MountPoint>, 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<Mutex<()>> = Lazy::new(|| Mutex::new(()));
let _lock = LOCK.lock().unwrap();

Expand Down
15 changes: 15 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c5c9c5e

Please sign in to comment.