about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-09-03 10:33:06 +0530
committerGitHub <noreply@github.com>2022-09-03 10:33:06 +0530
commitc42df986dab12d1cacb202f5c98588ec0e4ceb1d (patch)
treebd8e7c8d45473aacfd85117e679eb11b8dfc6f4b
parentdc8fe633d5812096008d94d47fa692264d327a46 (diff)
parentbc793c9fb2ae45b1e93cdd6ad1cd4ffe30587674 (diff)
downloadrust-c42df986dab12d1cacb202f5c98588ec0e4ceb1d.tar.gz
rust-c42df986dab12d1cacb202f5c98588ec0e4ceb1d.zip
Rollup merge of #101325 - ChrisDenton:BCRYPT_RNG_ALG_HANDLE, r=thomcc
Windows RNG: Use `BCRYPT_RNG_ALG_HANDLE` by default

This only changes a small amount of actual code, the rest is documentation outlining the history of this module as I feel it will be relevant to any future issues that might crop up.

The code change is to use the `BCRYPT_RNG_ALG_HANDLE` [pseudo-handle](https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles) by default, which simply uses the default RNG. Previously we used `BCRYPT_USE_SYSTEM_PREFERRED_RNG` which has to load the system configuration and then find and load that RNG. I suspect this was the cause of failures on some systems (e.g. due to corrupted config). However, this is admittedly speculation as I can't reproduce the issue myself (and it does seem quite rare even in the wild). Still, removing a possible point of failure is likely worthwhile in any case.

r? libs
-rw-r--r--library/std/src/sys/windows/c.rs2
-rw-r--r--library/std/src/sys/windows/rand.rs41
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 b4db77700aa..78d6ce3eff4 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 }