Skip to content

Commit 1d16e93

Browse files
committed
Workaround for mem safety in third party dlls
1 parent d51b6f9 commit 1d16e93

File tree

4 files changed

+55
-15
lines changed

4 files changed

+55
-15
lines changed

library/std/src/sys/fs/windows/remove_dir_all.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use core::sync::atomic::{Atomic, AtomicU32, Ordering};
3333

3434
use super::{AsRawHandle, DirBuff, File, FromRawHandle};
3535
use crate::sys::c;
36-
use crate::sys::pal::api::WinError;
36+
use crate::sys::pal::api::{UnicodeStrRef, WinError};
3737
use crate::thread;
3838

3939
// The maximum number of times to spin when waiting for deletes to complete.
@@ -90,9 +90,9 @@ fn open_link_no_reparse(
9090
static ATTRIBUTES: Atomic<u32> = AtomicU32::new(c::OBJ_DONT_REPARSE);
9191

9292
let result = unsafe {
93-
let mut path_str = c::UNICODE_STRING::from_ref(path);
93+
let path_str = UnicodeStrRef::from_slice(path);
9494
let mut object = c::OBJECT_ATTRIBUTES {
95-
ObjectName: &mut path_str,
95+
ObjectName: path_str.as_ptr(),
9696
RootDirectory: parent.as_raw_handle(),
9797
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
9898
..c::OBJECT_ATTRIBUTES::with_length()

library/std/src/sys/pal/windows/api.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
//! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example.
3131
3232
use core::ffi::c_void;
33+
use core::marker::PhantomData;
3334

3435
use super::c;
3536

@@ -291,3 +292,49 @@ impl WinError {
291292
pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT);
292293
// tidy-alphabetical-end
293294
}
295+
296+
/// A wrapper around a UNICODE_STRING that is equivalent to `&[u16]`.
297+
///
298+
/// It is preferable to use `from_slice_with_nul` for our own strings as a
299+
/// mitigation for #143078.
300+
#[derive(Copy, Clone)]
301+
pub struct UnicodeStrRef<'a> {
302+
s: c::UNICODE_STRING,
303+
lifetime: PhantomData<&'a [u16]>,
304+
}
305+
306+
static EMPTY_STRING_NULL_TERMINATED: &[u16] = &[0];
307+
308+
impl UnicodeStrRef<'_> {
309+
pub const EMPTY: Self = Self::from_slice(&[]);
310+
311+
const fn new(slice: &[u16], is_null_terminated: bool) -> Self {
312+
let (len, ptr) = if slice.is_empty() {
313+
// As a mitigation for #143078, an empty slice always points to a null-terminated string.
314+
(0, EMPTY_STRING_NULL_TERMINATED.as_ptr().cast_mut())
315+
} else {
316+
let len = slice.len() - (is_null_terminated as usize);
317+
(len * 2, slice.as_ptr().cast_mut())
318+
};
319+
Self {
320+
s: c::UNICODE_STRING { Length: len as _, MaximumLength: len as _, Buffer: ptr },
321+
lifetime: PhantomData,
322+
}
323+
}
324+
325+
pub const fn from_slice_with_nul(slice: &[u16]) -> Self {
326+
if !slice.is_empty() {
327+
debug_assert!(slice[slice.len() - 1] == 0);
328+
}
329+
Self::new(slice, true)
330+
}
331+
332+
pub const fn from_slice(slice: &[u16]) -> Self {
333+
Self::new(slice, false)
334+
}
335+
336+
/// Returns a pointer to the underlying UNICODE_STRING
337+
pub const fn as_ptr(&self) -> *const c::UNICODE_STRING {
338+
&self.s
339+
}
340+
}

library/std/src/sys/pal/windows/c.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ pub fn nt_success(status: NTSTATUS) -> bool {
3737
status >= 0
3838
}
3939

40-
impl UNICODE_STRING {
41-
pub fn from_ref(slice: &[u16]) -> Self {
42-
let len = size_of_val(slice);
43-
Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
44-
}
45-
}
46-
4740
impl OBJECT_ATTRIBUTES {
4841
pub fn with_length() -> Self {
4942
Self {

library/std/src/sys/pal/windows/pipe.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
22
use crate::ops::Neg;
33
use crate::os::windows::prelude::*;
4-
use crate::sys::api::utf16;
4+
use crate::sys::api::{self, wide_str};
55
use crate::sys::c;
66
use crate::sys::handle::Handle;
77
use crate::sys_common::{FromInner, IntoInner};
@@ -73,8 +73,8 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
7373
// Open a handle to the pipe filesystem (`\??\PIPE\`).
7474
// This will be used when creating a new annon pipe.
7575
let pipe_fs = {
76-
let path = c::UNICODE_STRING::from_ref(utf16!(r"\??\PIPE\"));
77-
object_attributes.ObjectName = &path;
76+
let path = api::UnicodeStrRef::from_slice_with_nul(wide_str!(r"\??\PIPE\"));
77+
object_attributes.ObjectName = path.as_ptr();
7878
let mut pipe_fs = ptr::null_mut();
7979
let status = c::NtOpenFile(
8080
&mut pipe_fs,
@@ -93,8 +93,8 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
9393

9494
// From now on we're using handles instead of paths to create and open pipes.
9595
// So set the `ObjectName` to a zero length string.
96-
let empty = c::UNICODE_STRING::default();
97-
object_attributes.ObjectName = &empty;
96+
let empty = api::UnicodeStrRef::EMPTY;
97+
object_attributes.ObjectName = empty.as_ptr();
9898

9999
// Create our side of the pipe for async access.
100100
let ours = {

0 commit comments

Comments
 (0)