Skip to content

Commit 7b66abe

Browse files
authored
Rollup merge of #114968 - ShE3py:unix-getsetenv-ub, r=thomcc
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
2 parents 33771df + 83c713b commit 7b66abe

File tree

3 files changed

+47
-27
lines changed

3 files changed

+47
-27
lines changed

library/std/src/sys/solid/os.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ pub fn current_exe() -> io::Result<PathBuf> {
8181

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

84+
pub fn env_read_lock() -> impl Drop {
85+
ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
86+
}
87+
8488
pub struct Env {
8589
iter: vec::IntoIter<(OsString, OsString)>,
8690
}
@@ -134,7 +138,7 @@ pub fn env() -> Env {
134138
}
135139

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

177-
if s.is_null() {
178-
None
179-
} else {
180-
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
181-
}
179+
if v.is_null() {
180+
Ok(None)
181+
} else {
182+
// SAFETY: `v` cannot be mutated while executing this line since we've a read lock
183+
let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();
184+
185+
Ok(Some(OsStringExt::from_vec(bytes)))
186+
}
187+
})
188+
.ok()
189+
.flatten()
182190
}
183191

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

library/std/src/sys/unix/os.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -594,16 +594,21 @@ pub fn env() -> Env {
594594
pub fn getenv(k: &OsStr) -> Option<OsString> {
595595
// environment variables with a nul byte can't be set, so their value is
596596
// always None as well
597-
let s = run_with_cstr(k.as_bytes(), |k| {
597+
run_with_cstr(k.as_bytes(), |k| {
598598
let _guard = env_read_lock();
599-
Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char)
599+
let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
600+
601+
if v.is_null() {
602+
Ok(None)
603+
} else {
604+
// SAFETY: `v` cannot be mutated while executing this line since we've a read lock
605+
let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();
606+
607+
Ok(Some(OsStringExt::from_vec(bytes)))
608+
}
600609
})
601-
.ok()?;
602-
if s.is_null() {
603-
None
604-
} else {
605-
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
606-
}
610+
.ok()
611+
.flatten()
607612
}
608613

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

library/std/src/sys/wasi/os.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -225,16 +225,23 @@ pub fn env() -> Env {
225225
}
226226

227227
pub fn getenv(k: &OsStr) -> Option<OsString> {
228-
let s = run_with_cstr(k.as_bytes(), |k| unsafe {
228+
// environment variables with a nul byte can't be set, so their value is
229+
// always None as well
230+
run_with_cstr(k.as_bytes(), |k| {
229231
let _guard = env_read_lock();
230-
Ok(libc::getenv(k.as_ptr()) as *const libc::c_char)
232+
let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
233+
234+
if v.is_null() {
235+
Ok(None)
236+
} else {
237+
// SAFETY: `v` cannot be mutated while executing this line since we've a read lock
238+
let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();
239+
240+
Ok(Some(OsStringExt::from_vec(bytes)))
241+
}
231242
})
232-
.ok()?;
233-
if s.is_null() {
234-
None
235-
} else {
236-
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
237-
}
243+
.ok()
244+
.flatten()
238245
}
239246

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

0 commit comments

Comments
 (0)