Closed a4lg closed 12 months ago
Yes, I think we should probably use TryFrom
and panic in cases where it is impractical to propagate the error.
It might be better to wrap the slice in a newtype that checks the maximum length and returns an error of its own if the slice is too large. Something like:
pub struct WSlice<'a, T> {
pub(crate) slice: *const T,
pub(crate) len: i32,
_phantom_slice: PhantomData<&'a [T]>,
}
impl<'a, T> TryFrom<&'a [T]> for WSlice<'a, T> {
type Error = SliceTooLongError;
fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
let len = i32::try_from(slice.len()).map_err(|_| SliceTooLongError)?;
let slice = slice.as_ptr();
Ok(Self { slice, len, _phantom_slice: PhantomData })
}
}
Then, change APIs that currently take slice references to take &WSlice<T>
instead of &[T]
.
This has the upside of no panics and no misbehavior, but the downside that it's more difficult to use.
Note that there are some cases where it's acceptable to just use i32::MAX
if the slice is too long. For example, GetClipboardFormatName
can't produce a clipboard format name longer than i32::MAX
characters, and unless I'm mistaken clipboard format names can't be longer than that anyway, so if the slice is longer than that, nothing bad will happen if i32::MAX
is passed to GetClipboardFormatName
instead of the real slice length.
My first idea was to fix this is to use regular slices and change the return type to Result<i32, SOME_NEW_ERROR_TYPE>
but @ahcodedthat's idea looks less breaking and easier to understand what have happened.
Yes, creating safe error somewhere is required but there's many of possible choices without making panics ...and that's why I'm not sure what to do (because no matter what we change, that would be a breaking change; I don't support making a panic in such easy consequences but the fact that the fix will break the compatibility suffers me).
Ping.
I was thinking of turning these into E_INVALIDARG
and just returning through the same Error
propagation path. Just haven't had time to rough it in but hope to do so soon.
Thanks for your response!
I understand that the work to avoid this issue wouldn't be easy and will take much time (and most notably, compatibility breaking). As long as this issue is not forgotten, I'm happy with it.
Here's a partial fix: #2699
Some wrappers inside the
windows
crate takes one or more slices as arguments.What I concern is, on current
windows
crate,slice.len()
is converted to another type without checking validity against the target type. As a result, it sometimes causes arithmetic overflow.For instance,
MultiByteToWideChar
Win32 API usesint
as the length type.Quoting
crates/libs/windows/src/Windows/Win32/Globalization/mod.rs
:OK, if we overflow
i32
, that would be a problem.Following test code intentionally exploits this and try to pass
0x1_0000_0003
-byte sized buffer toMultiByteToWideChar
. It is handled as3
-byte sized buffer in the wrapper and the result is corrupted.For
windows-sys
crate, I don't find any issues. The user must handle such conditions to use the API safely. However, inwindows
crate, slice length type is hidden inside the wrapper and there's no safety measures.I'm not sure what to do but I can say that some decision making will be required.
Additional Keywords: (potential) security, integer overflow