Recently there have been a number of vulnerabilities reported due to unsynchronized access to environment variable APIs such as
setenv(3), the latter of which is marked as
MT-Unsafe const:env by glibc.
- RUSTSEC-2020-0071: potential segfault in the
- RUSTSEC-2020-0159: potential segfault in
- flate2-rs: unsound due to calls to
getenvallowing safe data race
Notably these vulnerabilities were in some cases discovered via segfaults in real-world Rust programs.
The safe environmental accessor functions in
std::env are synchronized through OS-specific backends. In
cfg(unix) environments synchronization is provided by
std::sys::unix::os::ENV_LOCK, and the
std::sys::unix::os::env_read_lock wrapper function.
setenv wrapper functions in
std::sys::unix::os use this lock to synchronize access to environment variables.
Unfortunately, these are all private APIs, which means that there is no way for FFI users who need to directly invoke
setenv or other e.g. libc functions that vicariously invoke them, such as
Note that while concurrent access to environment variables is safe in Rust, some platforms only expose inherently unsafe non-threadsafe APIs for inspecting the environment. As a result, extra care needs to be taken when auditing calls to unsafe external FFI functions to ensure that any external environment accesses are properly synchronized with accesses in Rust.
Missing from this description is a solution for soundly invoking any APIs which might need to acquire something like
ENV_LOCK first in order to ensure synchronized access to the environment.
As far as I can tell there are only two options here:
- Add APIs that FFI users can use to synchronize access to the environment
- Rewrite functions like
localtime_rin safe Rust, using
std::env's safe, already-synchronized API for environment access
Personally I really like option 2, but so far various people have looked at porting
localtime_r to safe Rust and souring on it due to the complexity. I really hope this still happens and it would be a huge benefit to the ecosystem.
But really I opened this issue to talk about option 1: is there a safe API that makes sense to expose from
std? Could there be something like a
std::os::unix::env module which provides something like
write_lock functions which an FFI caller can obtain before calling into APIs that invoke