Skip to content

Commit 160fa8c

Browse files
authored
zeroize: impl Zeroize for MaybeUninit and remove some unsafe (#900)
1 parent 50fd775 commit 160fa8c

File tree

6 files changed

+55
-68
lines changed

6 files changed

+55
-68
lines changed

.github/workflows/zeroize.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
strategy:
2727
matrix:
2828
rust:
29-
- 1.56.0 # MSRV
29+
- 1.60.0 # MSRV
3030
- stable
3131
target:
3232
- armv7a-none-eabi
@@ -53,7 +53,7 @@ jobs:
5353
# 32-bit Linux
5454
- target: i686-unknown-linux-gnu
5555
platform: ubuntu-latest
56-
rust: 1.56.0 # MSRV
56+
rust: 1.60.0 # MSRV
5757
deps: sudo apt update && sudo apt install gcc-multilib
5858
- target: i686-unknown-linux-gnu
5959
platform: ubuntu-latest
@@ -63,23 +63,23 @@ jobs:
6363
# 64-bit Linux
6464
- target: x86_64-unknown-linux-gnu
6565
platform: ubuntu-latest
66-
rust: 1.56.0 # MSRV
66+
rust: 1.60.0 # MSRV
6767
- target: x86_64-unknown-linux-gnu
6868
platform: ubuntu-latest
6969
rust: stable
7070

7171
# 64-bit macOS x86_64
7272
- target: x86_64-apple-darwin
7373
platform: macos-latest
74-
rust: 1.56.0 # MSRV
74+
rust: 1.60.0 # MSRV
7575
- target: x86_64-apple-darwin
7676
platform: macos-latest
7777
rust: stable
7878

7979
# 64-bit Windows
8080
- target: x86_64-pc-windows-msvc
8181
platform: windows-latest
82-
rust: 1.56.0 # MSRV
82+
rust: 1.60.0 # MSRV
8383
- target: x86_64-pc-windows-msvc
8484
platform: windows-latest
8585
rust: stable
@@ -102,7 +102,7 @@ jobs:
102102
include:
103103
# PPC32
104104
- target: powerpc-unknown-linux-gnu
105-
rust: 1.56.0 # MSRV
105+
rust: 1.60.0 # MSRV
106106
- target: powerpc-unknown-linux-gnu
107107
rust: stable
108108
runs-on: ubuntu-latest
@@ -122,7 +122,7 @@ jobs:
122122
matrix:
123123
include:
124124
- target: aarch64-unknown-linux-gnu
125-
rust: 1.59.0
125+
rust: 1.60.0
126126
- target: aarch64-unknown-linux-gnu
127127
rust: stable
128128
runs-on: ubuntu-latest

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ This repository contains various utility crates used in the RustCrypto project.
2121
| [`inout`] | [![crates.io](https://img.shields.io/crates/v/inout.svg)](https://crates.io/crates/inout) | [![Documentation](https://docs.rs/inout/badge.svg)](https://docs.rs/inout) | ![MSRV 1.56][msrv-1.56] | Custom reference types for code generic over in-place and buffer-to-buffer modes of operation. |
2222
| [`opaque-debug`] | [![crates.io](https://img.shields.io/crates/v/opaque-debug.svg)](https://crates.io/crates/opaque-debug) | [![Documentation](https://docs.rs/opaque-debug/badge.svg)](https://docs.rs/opaque-debug) | ![MSRV 1.41][msrv-1.41] | Macro for opaque `Debug` trait implementation |
2323
| [`wycheproof2blb`] | | | | Utility for converting [Wycheproof] test vectors to the blobby format |
24-
| [`zeroize`] | [![crates.io](https://img.shields.io/crates/v/zeroize.svg)](https://crates.io/crates/zeroize) | [![Documentation](https://docs.rs/zeroize/badge.svg)](https://docs.rs/zeroize) | ![MSRV 1.51][msrv-1.51] | Securely zero memory while avoiding compiler optimizations |
24+
| [`zeroize`] | [![crates.io](https://img.shields.io/crates/v/zeroize.svg)](https://crates.io/crates/zeroize) | [![Documentation](https://docs.rs/zeroize/badge.svg)](https://docs.rs/zeroize) | ![MSRV 1.60][msrv-1.60] | Securely zero memory while avoiding compiler optimizations |
2525

2626
## License
2727

@@ -52,6 +52,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
5252
[msrv-1.56]: https://img.shields.io/badge/rustc-1.56.0+-blue.svg
5353
[msrv-1.57]: https://img.shields.io/badge/rustc-1.57.0+-blue.svg
5454
[msrv-1.59]: https://img.shields.io/badge/rustc-1.59.0+-blue.svg
55+
[msrv-1.60]: https://img.shields.io/badge/rustc-1.60.0+-blue.svg
5556

5657
[//]: # (crates)
5758

zeroize/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ readme = "README.md"
1515
categories = ["cryptography", "memory-management", "no-std", "os"]
1616
keywords = ["memory", "memset", "secure", "volatile", "zero"]
1717
edition = "2021"
18-
rust-version = "1.56"
18+
rust-version = "1.60"
1919

2020
[dependencies]
2121
serde = { version = "1.0", default-features = false, optional = true }

zeroize/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ thereof, implemented in pure Rust with no usage of FFI or assembly.
3636

3737
## Minimum Supported Rust Version
3838

39-
Rust **1.56** or newer.
39+
Rust **1.60** or newer.
4040

4141
In the future, we reserve the right to change MSRV (i.e. MSRV is out-of-scope
4242
for this crate's SemVer guarantees), however when we do it will be accompanied by
@@ -64,7 +64,7 @@ dual licensed as above, without any additional terms or conditions.
6464
[docs-image]: https://docs.rs/zeroize/badge.svg
6565
[docs-link]: https://docs.rs/zeroize/
6666
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
67-
[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
67+
[rustc-image]: https://img.shields.io/badge/rustc-1.60+-blue.svg
6868
[build-image]: https://github.com/RustCrypto/utils/actions/workflows/zeroize.yml/badge.svg
6969
[build-link]: https://github.com/RustCrypto/utils/actions/workflows/zeroize.yml
7070

zeroize/src/aarch64.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! [`Zeroize`] impls for ARM64 SIMD registers.
22
//!
33
//! Gated behind the `aarch64` feature: MSRV 1.59
4-
//! (the overall crate is MSRV 1.56)
4+
//! (the overall crate is MSRV 1.60)
55
66
use crate::{atomic_fence, volatile_write, Zeroize};
77

zeroize/src/lib.rs

+42-56
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//!
3131
//! ## Minimum Supported Rust Version
3232
//!
33-
//! Requires Rust **1.56** or newer.
33+
//! Requires Rust **1.60** or newer.
3434
//!
3535
//! In the future, we reserve the right to change MSRV (i.e. MSRV is out-of-scope
3636
//! for this crate's SemVer guarantees), however when we do it will be accompanied
@@ -263,10 +263,7 @@ use core::{
263263
};
264264

265265
#[cfg(feature = "alloc")]
266-
use {
267-
alloc::{boxed::Box, string::String, vec::Vec},
268-
core::slice,
269-
};
266+
use alloc::{boxed::Box, string::String, vec::Vec};
270267

271268
#[cfg(feature = "std")]
272269
use std::ffi::CString;
@@ -315,18 +312,28 @@ macro_rules! impl_zeroize_with_default {
315312

316313
#[rustfmt::skip]
317314
impl_zeroize_with_default! {
318-
bool, char,
315+
PhantomPinned, (), bool, char,
319316
f32, f64,
320317
i8, i16, i32, i64, i128, isize,
321318
u8, u16, u32, u64, u128, usize
322319
}
323320

321+
/// `PhantomPinned` is zero sized so provide a ZeroizeOnDrop implementation.
322+
impl ZeroizeOnDrop for PhantomPinned {}
323+
324+
/// `()` is zero sized so provide a ZeroizeOnDrop implementation.
325+
impl ZeroizeOnDrop for () {}
326+
324327
macro_rules! impl_zeroize_for_non_zero {
325328
($($type:ty),+) => {
326329
$(
327330
impl Zeroize for $type {
328331
fn zeroize(&mut self) {
329-
volatile_write(self, unsafe { <$type>::new_unchecked(1) });
332+
const ONE: $type = match <$type>::new(1) {
333+
Some(one) => one,
334+
None => unreachable!(),
335+
};
336+
volatile_write(self, ONE);
330337
atomic_fence();
331338
}
332339
}
@@ -371,7 +378,7 @@ where
371378
/// Impl [`ZeroizeOnDrop`] on arrays of types that impl [`ZeroizeOnDrop`].
372379
impl<Z, const N: usize> ZeroizeOnDrop for [Z; N] where Z: ZeroizeOnDrop {}
373380

374-
impl<'a, Z> Zeroize for IterMut<'a, Z>
381+
impl<Z> Zeroize for IterMut<'_, Z>
375382
where
376383
Z: Zeroize,
377384
{
@@ -405,25 +412,39 @@ where
405412
// The memory pointed to by `self` is valid for `mem::size_of::<Self>()` bytes.
406413
// It is also properly aligned, because `u8` has an alignment of `1`.
407414
unsafe {
408-
volatile_set(self as *mut _ as *mut u8, 0, mem::size_of::<Self>());
415+
volatile_set((self as *mut Self).cast::<u8>(), 0, mem::size_of::<Self>());
409416
}
410417

411-
// Ensures self is overwritten with the default bit pattern. volatile_write can't be
418+
// Ensures self is overwritten with the `None` bit pattern. volatile_write can't be
412419
// used because Option<Z> is not copy.
413420
//
414421
// Safety:
415422
//
416-
// self is safe to replace with the default, which the take() call above should have
423+
// self is safe to replace with `None`, which the take() call above should have
417424
// already done semantically. Any value which needed to be dropped will have been
418425
// done so by take().
419-
unsafe { ptr::write_volatile(self, Option::default()) }
426+
unsafe { ptr::write_volatile(self, None) }
420427

421428
atomic_fence();
422429
}
423430
}
424431

425432
impl<Z> ZeroizeOnDrop for Option<Z> where Z: ZeroizeOnDrop {}
426433

434+
/// Impl [`Zeroize`] on [`MaybeUninit`] types.
435+
///
436+
/// This fills the memory with zeroes.
437+
/// Note that this ignore invariants that `Z` might have, because
438+
/// [`MaybeUninit`] removes all invariants.
439+
impl<Z> Zeroize for MaybeUninit<Z> {
440+
fn zeroize(&mut self) {
441+
// Safety:
442+
// `MaybeUninit` is valid for any byte pattern, including zeros.
443+
unsafe { ptr::write_volatile(self, MaybeUninit::zeroed()) }
444+
atomic_fence();
445+
}
446+
}
447+
427448
/// Impl [`Zeroize`] on slices of [`MaybeUninit`] types.
428449
///
429450
/// This impl can eventually be optimized using an memset intrinsic,
@@ -435,7 +456,7 @@ impl<Z> ZeroizeOnDrop for Option<Z> where Z: ZeroizeOnDrop {}
435456
/// [`MaybeUninit`] removes all invariants.
436457
impl<Z> Zeroize for [MaybeUninit<Z>] {
437458
fn zeroize(&mut self) {
438-
let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
459+
let ptr = self.as_mut_ptr().cast::<MaybeUninit<u8>>();
439460
let size = self.len().checked_mul(mem::size_of::<Z>()).unwrap();
440461
assert!(size <= isize::MAX as usize);
441462

@@ -445,7 +466,7 @@ impl<Z> Zeroize for [MaybeUninit<Z>] {
445466
// and it is backed by a single allocated object for at least `self.len() * size_pf::<Z>()` bytes.
446467
// and 0 is a valid value for `MaybeUninit<Z>`
447468
// The memory of the slice should not wrap around the address space.
448-
unsafe { volatile_set(ptr, MaybeUninit::new(0), size) }
469+
unsafe { volatile_set(ptr, MaybeUninit::zeroed(), size) }
449470
atomic_fence();
450471
}
451472
}
@@ -492,47 +513,22 @@ impl<Z> Zeroize for PhantomData<Z> {
492513
/// [`PhantomData` is always zero sized so provide a ZeroizeOnDrop implementation.
493514
impl<Z> ZeroizeOnDrop for PhantomData<Z> {}
494515

495-
/// `PhantomPinned` is zero sized so provide a Zeroize implementation.
496-
impl Zeroize for PhantomPinned {
497-
fn zeroize(&mut self) {}
498-
}
499-
500-
/// `PhantomPinned` is zero sized so provide a ZeroizeOnDrop implementation.
501-
impl ZeroizeOnDrop for PhantomPinned {}
502-
503-
/// `()` is zero sized so provide a Zeroize implementation.
504-
impl Zeroize for () {
505-
fn zeroize(&mut self) {}
506-
}
507-
508-
/// `()` is zero sized so provide a ZeroizeOnDrop implementation.
509-
impl ZeroizeOnDrop for () {}
510-
511-
/// Generic implementation of Zeroize for tuples up to 10 parameters.
512-
impl<A: Zeroize> Zeroize for (A,) {
513-
fn zeroize(&mut self) {
514-
self.0.zeroize();
515-
}
516-
}
517-
518-
/// Generic implementation of ZeroizeOnDrop for tuples up to 10 parameters.
519-
impl<A: ZeroizeOnDrop> ZeroizeOnDrop for (A,) {}
520-
521516
macro_rules! impl_zeroize_tuple {
522517
( $( $type_name:ident ),+ ) => {
523-
impl<$($type_name: Zeroize),+> Zeroize for ($($type_name),+) {
518+
impl<$($type_name: Zeroize),+> Zeroize for ($($type_name,)+) {
524519
fn zeroize(&mut self) {
525520
#[allow(non_snake_case)]
526-
let ($($type_name),+) = self;
521+
let ($($type_name,)+) = self;
527522
$($type_name.zeroize());+
528523
}
529524
}
530525

531-
impl<$($type_name: ZeroizeOnDrop),+> ZeroizeOnDrop for ($($type_name),+) { }
526+
impl<$($type_name: ZeroizeOnDrop),+> ZeroizeOnDrop for ($($type_name,)+) { }
532527
}
533528
}
534529

535530
// Generic implementations for tuples up to 10 parameters.
531+
impl_zeroize_tuple!(A);
536532
impl_zeroize_tuple!(A, B);
537533
impl_zeroize_tuple!(A, B, C);
538534
impl_zeroize_tuple!(A, B, C, D);
@@ -561,17 +557,7 @@ where
561557
self.clear();
562558

563559
// Zero the full capacity of `Vec`.
564-
// Safety:
565-
//
566-
// This is safe, because `Vec` never allocates more than `isize::MAX` bytes.
567-
// This exact use case is even mentioned in the documentation of `pointer::add`.
568-
// This is safe because MaybeUninit ignores all invariants,
569-
// so we can create a slice of MaybeUninit<Z> using the full capacity of the Vec
570-
let uninit_slice = unsafe {
571-
slice::from_raw_parts_mut(self.as_mut_ptr() as *mut MaybeUninit<Z>, self.capacity())
572-
};
573-
574-
uninit_slice.zeroize();
560+
self.spare_capacity_mut().zeroize();
575561
}
576562
}
577563

@@ -621,11 +607,11 @@ impl Zeroize for CString {
621607
// contain a trailing zero byte
622608
let this = mem::take(self);
623609

624-
// - CString::into_bytes calls ::into_vec which takes ownership of the heap pointer
610+
// - CString::into_bytes_with_nul calls ::into_vec which takes ownership of the heap pointer
625611
// as a Vec<u8>
626612
// - Calling .zeroize() on the resulting vector clears out the bytes
627613
// From: https://github.com/RustCrypto/utils/pull/759#issuecomment-1087976570
628-
let mut buf = this.into_bytes();
614+
let mut buf = this.into_bytes_with_nul();
629615
buf.zeroize();
630616

631617
// expect() should never fail, because zeroize() truncates the Vec

0 commit comments

Comments
 (0)