Skip to content

Commit 97ab3e8

Browse files
dakrojeda
authored andcommitted
rust: alloc: fix dangling pointer in VecExt<T>::reserve()
Currently, a Vec<T>'s ptr value, after calling Vec<T>::new(), is initialized to Unique::dangling(). Hence, in VecExt<T>::reserve(), we're passing a dangling pointer (instead of NULL) to krealloc() whenever a new Vec<T>'s backing storage is allocated through VecExt<T> extension functions. This only works as long as align_of::<T>(), used by Unique::dangling() to derive the dangling pointer, resolves to a value between 0x0 and ZERO_SIZE_PTR (0x10) and krealloc() hence treats it the same as a NULL pointer however. This isn't a case we should rely on, since there may be types whose alignment may exceed the range still covered by krealloc(), plus other kernel allocators are not as tolerant either. Instead, pass a real NULL pointer to krealloc_aligned() if Vec<T>'s capacity is zero. Fixes: 5ab560c ("rust: alloc: update `VecExt` to take allocation flags") Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Boqun Feng <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> Reviewed-by: Wedson Almeida Filho <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Solved `use` conflict and applied the `if`-instead-of-`match` change discussed in the list. - Miguel ] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 56f64b3 commit 97ab3e8

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

rust/kernel/alloc/vec_ext.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
use super::{AllocError, Flags};
66
use alloc::vec::Vec;
7+
use core::ptr;
78

89
/// Extensions to [`Vec`].
910
pub trait VecExt<T>: Sized {
@@ -134,14 +135,20 @@ impl<T> VecExt<T> for Vec<T> {
134135
let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
135136
let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
136137

137-
let (ptr, len, cap) = destructure(self);
138+
let (old_ptr, len, cap) = destructure(self);
139+
140+
// We need to make sure that `ptr` is either NULL or comes from a previous call to
141+
// `krealloc_aligned`. A `Vec<T>`'s `ptr` value is not guaranteed to be NULL and might be
142+
// dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T>`'s capacity
143+
// to be zero if no memory has been allocated yet.
144+
let ptr = if cap == 0 { ptr::null_mut() } else { old_ptr };
138145

139146
// SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to
140147
// `krealloc_aligned`. We also verified that the type is not a ZST.
141148
let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) };
142149
if new_ptr.is_null() {
143150
// SAFETY: We are just rebuilding the existing `Vec` with no changes.
144-
unsafe { rebuild(self, ptr, len, cap) };
151+
unsafe { rebuild(self, old_ptr, len, cap) };
145152
Err(AllocError)
146153
} else {
147154
// SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap

0 commit comments

Comments
 (0)