[llvm] aab9e9d - [Support, Windows] Tolerate failure of CryptGenRandom
Simon Tatham via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 7 01:21:23 PDT 2020
Author: Simon Tatham
Date: 2020-04-07T09:18:12+01:00
New Revision: aab9e9de4d9925617bb9bc3891fa96107b615149
URL: https://github.com/llvm/llvm-project/commit/aab9e9de4d9925617bb9bc3891fa96107b615149
DIFF: https://github.com/llvm/llvm-project/commit/aab9e9de4d9925617bb9bc3891fa96107b615149.diff
LOG: [Support,Windows] Tolerate failure of CryptGenRandom
Summary:
In `Unix/Process.inc`, we seed a random number generator from
`/dev/urandom` if possible, but if not, we're happy to fall back to
ordinary pseudorandom strategies, like the current time and PID.
The corresponding function on Windows calls `CryptGenRandom`, but it
//doesn't// have a fallback if that strategy fails. But `CryptGenRandom`
//can// fail, if a cryptography provider isn't properly initialized, or
occasionally (by our observation) simply intermittently.
If it's reasonable on Unix to implement traditional pseudorandom-number
seeding as a fallback, then it's surely reasonable to do the same on
Windows. So this patch adds a last-ditch use of ordinary rand(), using
much the same strategy as the Unix fallback code.
Reviewers: hans, sammccall
Reviewed By: hans
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77553
Added:
Modified:
llvm/lib/Support/Windows/Process.inc
Removed:
################################################################################
diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc
index 518ecdb98896..6eb4a5eb7457 100644
--- a/llvm/lib/Support/Windows/Process.inc
+++ b/llvm/lib/Support/Windows/Process.inc
@@ -439,18 +439,38 @@ const char *Process::ResetColor() {
return 0;
}
+static unsigned GetRandomNumberSeed() {
+ // Generate a random number seed from the millisecond-resolution Windows
+ // system clock and the current process id.
+ FILETIME Time;
+ GetSystemTimeAsFileTime(&Time);
+ DWORD Pid = GetCurrentProcessId();
+ return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid);
+}
+
+static unsigned GetPseudoRandomNumber() {
+ // Arrange to call srand once when this function is first used, and
+ // otherwise (if GetRandomNumber always succeeds in using
+ // CryptGenRandom) don't bother at all.
+ static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);
+ (void)x;
+ return ::rand();
+}
+
unsigned Process::GetRandomNumber() {
+ // Try to use CryptGenRandom.
HCRYPTPROV HCPC;
- if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT))
- ReportLastErrorFatal("Could not acquire a cryptographic context");
-
- ScopedCryptContext CryptoProvider(HCPC);
- unsigned Ret;
- if (!::CryptGenRandom(CryptoProvider, sizeof(Ret),
- reinterpret_cast<BYTE *>(&Ret)))
- ReportLastErrorFatal("Could not generate a random number");
- return Ret;
+ if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ ScopedCryptContext CryptoProvider(HCPC);
+ unsigned Ret;
+ if (::CryptGenRandom(CryptoProvider, sizeof(Ret),
+ reinterpret_cast<BYTE *>(&Ret)))
+ return Ret;
+ }
+
+ // If that fails, fall back to pseudo-random numbers.
+ return GetPseudoRandomNumber();
}
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
More information about the llvm-commits
mailing list