Skip to content

Commit

Permalink
Rollup merge of #114968 - ShE3py:unix-getsetenv-ub, r=thomcc
Browse files Browse the repository at this point in the history
Fix UB in `std::sys::os::getenv()`

Fixes #114949.

Reduced the loops to 1k iterations (100k was taking way too long), Miri no longer shows any UB.

`@rustbot` label +A-process +C-bug +I-unsound +O-unix
  • Loading branch information
matthiaskrgr authored Aug 20, 2023
2 parents 33771df + 83c713b commit 7b66abe
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 27 deletions.
30 changes: 19 additions & 11 deletions library/std/src/sys/solid/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ pub fn current_exe() -> io::Result<PathBuf> {

static ENV_LOCK: RwLock<()> = RwLock::new(());

pub fn env_read_lock() -> impl Drop {
ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
}

pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
Expand Down Expand Up @@ -134,7 +138,7 @@ pub fn env() -> Env {
}

unsafe {
let _guard = ENV_LOCK.read();
let _guard = env_read_lock();
let mut result = Vec::new();
if !environ.is_null() {
while !(*environ).is_null() {
Expand Down Expand Up @@ -168,17 +172,21 @@ pub fn env() -> Env {
pub fn getenv(k: &OsStr) -> Option<OsString> {
// environment variables with a nul byte can't be set, so their value is
// always None as well
let s = run_with_cstr(k.as_bytes(), |k| {
let _guard = ENV_LOCK.read();
Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char)
})
.ok()?;
run_with_cstr(k.as_bytes(), |k| {
let _guard = env_read_lock();
let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;

if s.is_null() {
None
} else {
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
}
if v.is_null() {
Ok(None)
} else {
// SAFETY: `v` cannot be mutated while executing this line since we've a read lock
let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();

Ok(Some(OsStringExt::from_vec(bytes)))
}
})
.ok()
.flatten()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
Expand Down
21 changes: 13 additions & 8 deletions library/std/src/sys/unix/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,16 +594,21 @@ pub fn env() -> Env {
pub fn getenv(k: &OsStr) -> Option<OsString> {
// environment variables with a nul byte can't be set, so their value is
// always None as well
let s = run_with_cstr(k.as_bytes(), |k| {
run_with_cstr(k.as_bytes(), |k| {
let _guard = env_read_lock();
Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char)
let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;

if v.is_null() {
Ok(None)
} else {
// SAFETY: `v` cannot be mutated while executing this line since we've a read lock
let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();

Ok(Some(OsStringExt::from_vec(bytes)))
}
})
.ok()?;
if s.is_null() {
None
} else {
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
}
.ok()
.flatten()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
Expand Down
23 changes: 15 additions & 8 deletions library/std/src/sys/wasi/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,16 +225,23 @@ pub fn env() -> Env {
}

pub fn getenv(k: &OsStr) -> Option<OsString> {
let s = run_with_cstr(k.as_bytes(), |k| unsafe {
// environment variables with a nul byte can't be set, so their value is
// always None as well
run_with_cstr(k.as_bytes(), |k| {
let _guard = env_read_lock();
Ok(libc::getenv(k.as_ptr()) as *const libc::c_char)
let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;

if v.is_null() {
Ok(None)
} else {
// SAFETY: `v` cannot be mutated while executing this line since we've a read lock
let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();

Ok(Some(OsStringExt::from_vec(bytes)))
}
})
.ok()?;
if s.is_null() {
None
} else {
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
}
.ok()
.flatten()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
Expand Down

0 comments on commit 7b66abe

Please sign in to comment.