Dangerous use of ?Sized bound on copy_val leads to out-of-bounds read
Description
The copy_val function takes two parameters of generic type T. And T has the bound ?Sized, which indicates that T may not necessarily implement the Sized trait. This means that T may not have static size.
#[inline]
pub fn copy_val<T: ?Sized>(dst: &mut T, src: &T) {
#[cfg(target_os = "solana")]
// SAFETY: dst and src are of same type therefore the size is the same
unsafe {
syscalls::sol_memcpy_(
dst as *mut T as *mut u8,
src as *const T as *const u8,
core::mem::size_of_val(dst) as u64,
);
}
#[cfg(not(target_os = "solana"))]
core::hint::black_box((dst, src));
}As a result, two instances of T may have differing sizes. The copy_val function uses the size of the first parameter, dst, to determine how much of src to copy over. Because these instances of T may differ in size, it can result in the situation where bytes are read past the end of src and into potentially uninitialized memory or other fields.
Impact
This may lead to an out-of-bounds read against src. Reading out-of-bounds may leak sensitive data not intended to be read by the program, or otherwise lead to undefined behavior by reading bytes that were not meant to be read.
Recommendations
Remove the ?Sized constraint as T will assume Sized by default.