From bc793c9fb2ae45b1e93cdd6ad1cd4ffe30587674 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 2 Sep 2022 13:23:52 +0100 Subject: [PATCH] Use `BCRYPT_RNG_ALG_HANDLE` by default Also briefly document the history of `sys/windows/rand.rs` as they may be relevant to any future changes. --- library/std/src/sys/windows/c.rs | 2 +- library/std/src/sys/windows/rand.rs | 41 ++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index c99c8efe436..270294d13df 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -285,7 +285,7 @@ pub fn nt_success(status: NTSTATUS) -> bool { status >= 0 } -pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; +pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81; #[repr(C)] pub struct UNICODE_STRING { diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index f8fd93a7398..8b969788436 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -1,16 +1,49 @@ +//! # Random key generation +//! +//! This module wraps the RNG provided by the OS. There are a few different +//! ways to interface with the OS RNG so it's worth exploring each of the options. +//! Note that at the time of writing these all go through the (undocumented) +//! `bcryptPrimitives.dll` but they use different route to get there. +//! +//! Originally we were using [`RtlGenRandom`], however that function is +//! deprecated and warns it "may be altered or unavailable in subsequent versions". +//! +//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG` +//! flag to query and find the system configured RNG. However, this change caused a small +//! but significant number of users to experience panics caused by a failure of +//! this function. See [#94098]. +//! +//! The current version changes this to use the `BCRYPT_RNG_ALG_HANDLE` +//! [Pseudo-handle], which gets the default RNG algorithm without querying the +//! system preference thus hopefully avoiding the previous issue. +//! This is only supported on Windows 10+ so a fallback is used for older versions. +//! +//! [#94098]: https://github.com/rust-lang/rust/issues/94098 +//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom +//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom +//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles use crate::io; use crate::mem; use crate::ptr; use crate::sys::c; +/// Generates high quality secure random keys for use by [`HashMap`]. +/// +/// This is used to seed the default [`RandomState`]. +/// +/// [`HashMap`]: crate::collections::HashMap +/// [`RandomState`]: crate::collections::hash_map::RandomState pub fn hashmap_random_keys() -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { + let size = mem::size_of_val(&v).try_into().unwrap(); c::BCryptGenRandom( - ptr::null_mut(), - &mut v as *mut _ as *mut u8, - mem::size_of_val(&v) as c::ULONG, - c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, + // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+. + // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails. + ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE), + ptr::addr_of_mut!(v).cast(), + size, + 0, ) }; if ret != 0 { fallback_rng() } else { v }