Skip to content

Commit 9a2610e

Browse files
Merge pull request #341 from aticu/develop
zeroize: zeroize entire capacity of `Vec`
2 parents a8b673d + 78aa2f5 commit 9a2610e

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

AUTHORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ contributions under the terms of the [Apache License, Version 2.0]
1515
* David Tolnay ([@dtolnay](https://github.com/dtolnay))
1616
* Kai Ren ([@tyranron](https://github.com/tyranron))
1717
* Murarth ([@murarth](https://github.com/murarth))
18+
* Niclas Schwarzlose ([@aticu](https://github.com/aticu))
1819
* Yin Guanhao ([@sopium](https://github.com/sopium))
1920
* Will Speak ([@iwillspeak](https://github.com/iwillspeak))

zeroize/src/lib.rs

+63
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,32 @@ where
325325
/// previous reallocations did not leave values on the heap.
326326
fn zeroize(&mut self) {
327327
self.iter_mut().zeroize();
328+
329+
// Zero the capacity of the `Vec` that is not initialized.
330+
{
331+
// Safety:
332+
//
333+
// This is safe, because `Vec` never allocates more than `isize::MAX` bytes.
334+
// This exact use case is even mentioned in the documentation of `pointer::add`.
335+
let extra_capacity_start = unsafe { self.as_mut_ptr().add(self.len()) as *mut u8 };
336+
let extra_capacity_len = self.capacity().saturating_sub(self.len());
337+
338+
for i in 0..(extra_capacity_len * core::mem::size_of::<Z>()) {
339+
// Safety:
340+
//
341+
// This is safe, because `Vec` never allocates more than `isize::MAX` bytes.
342+
let current_ptr = unsafe { extra_capacity_start.add(i) };
343+
// Safety:
344+
//
345+
// `current_ptr` is valid, because it lies within the allocation of the `Vec`.
346+
// It is also properly aligned, because we write a `u8`, which has an alignment of
347+
// 1.
348+
unsafe { ptr::write_volatile(current_ptr, 0) };
349+
}
350+
351+
atomic_fence();
352+
}
353+
328354
self.clear();
329355
}
330356
}
@@ -458,6 +484,43 @@ mod tests {
458484
assert!(vec.is_empty());
459485
}
460486

487+
#[cfg(feature = "alloc")]
488+
#[test]
489+
fn zeroize_vec_entire_capacity() {
490+
#[derive(Clone)]
491+
struct PanicOnNonZeroDrop(u64);
492+
493+
impl Zeroize for PanicOnNonZeroDrop {
494+
fn zeroize(&mut self) {
495+
self.0 = 0;
496+
}
497+
}
498+
499+
impl Drop for PanicOnNonZeroDrop {
500+
fn drop(&mut self) {
501+
if self.0 != 0 {
502+
panic!("dropped non-zeroized data");
503+
}
504+
}
505+
}
506+
507+
// Ensure that the entire capacity of the vec is zeroized and that no unitinialized data
508+
// is ever interpreted as initialized
509+
let mut vec = vec![PanicOnNonZeroDrop(42); 2];
510+
511+
unsafe {
512+
vec.set_len(1);
513+
}
514+
515+
vec.zeroize();
516+
517+
unsafe {
518+
vec.set_len(2);
519+
}
520+
521+
drop(vec);
522+
}
523+
461524
#[cfg(feature = "alloc")]
462525
#[test]
463526
fn zeroize_string() {

0 commit comments

Comments
 (0)