These are the APIs that generally would be recommended to use. For
RtlGenRandom, there's also the alternative that we could try to
load it with LoadLibrary+GetProcAddress. (If we link directly against
it here, we need the winstorecompat replacement for the function
too.)

Signed-off-by: Martin Storsjö <[email protected]>
---
I'm not really sure if this is worthwhile doing though; we already
have the one fallback function that always works for us here, while
these other ones just add more code for little reason.
---
 mingw-w64-crt/ssp/stack_chk_guard.c | 56 +++++++++++++++++++++++++----
 1 file changed, 49 insertions(+), 7 deletions(-)

diff --git a/mingw-w64-crt/ssp/stack_chk_guard.c 
b/mingw-w64-crt/ssp/stack_chk_guard.c
index 3ff22e020..ffc59e1a6 100644
--- a/mingw-w64-crt/ssp/stack_chk_guard.c
+++ b/mingw-w64-crt/ssp/stack_chk_guard.c
@@ -6,22 +6,64 @@
 
 #define _CRT_RAND_S
 #include <stdlib.h>
+#include <windows.h>
+#include <bcrypt.h>
 #include <stdint.h>
+#include <ntsecapi.h>
 
 void *__stack_chk_guard;
 
 static void __cdecl __attribute__((__constructor__)) init(void)
 {
+  HMODULE bcrypt;
   unsigned int ui;
   if (__stack_chk_guard != 0)
     return;
 
-  // Call rand_s from the CRT; this uses a high quality random source
-  // RtlGenRandom internally. This function is available since XP, and is
-  // callable in WinStore mode too (since it's from the CRT).
-  // In the case of msvcrt.dll, our import library provides a small wrapper
-  // which tries to load the function dynamically, and falls back on
-  // using RtlRandomGen if not available.
+  // First try to generate the random number using BCrypt. This is the
+  // preferred approach. However, BCrypt is only available since Vista
+  // and we still support XP, so this has to be fetched and tested at
+  // runtime. (For WinStore apps, BCrypt is available only since Windows 10.
+  // But in WinStore builds, LoadLibrary isn't allowed, and libwinstorecompat
+  // and libwindowsappcompat would override LoadLibrary with a stub that
+  // returns NULL.)
+  //
+  // Also, if we'd link directly against this API, the compiler driver
+  // would need to add -lbcrypt to the linking command line by default.
+  //
+  // Since this is fetched with LoadLibrary/GetProcAddress, we can't
+  // provide/override it for builds with winstorecompat.
+  bcrypt = LoadLibraryW(L"bcrypt.dll");
+  if (bcrypt) {
+    NTSTATUS (WINAPI *pBCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE *, 
LPCWSTR, LPCWSTR, ULONG);
+    NTSTATUS (WINAPI *pBCryptGenRandom)(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, 
ULONG);
+    NTSTATUS (WINAPI *pBCryptCloseAlgorithmProvider)(BCRYPT_ALG_HANDLE, ULONG);
+    pBCryptOpenAlgorithmProvider = (void*)GetProcAddress(bcrypt, 
"BCryptOpenAlgorithmProvider");
+    pBCryptGenRandom = (void*)GetProcAddress(bcrypt, "BCryptGenRandom");
+    pBCryptCloseAlgorithmProvider = (void*)GetProcAddress(bcrypt, 
"BCryptCloseAlgorithmProvider");
+
+    if (pBCryptOpenAlgorithmProvider && pBCryptGenRandom && 
pBCryptCloseAlgorithmProvider) {
+      BCRYPT_ALG_HANDLE alg;
+      if (BCRYPT_SUCCESS(pBCryptOpenAlgorithmProvider(&alg, 
BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) {
+        pBCryptGenRandom(alg, (void*)&__stack_chk_guard, 
sizeof(__stack_chk_guard), 0);
+        pBCryptCloseAlgorithmProvider(alg, 0);
+        FreeLibrary(bcrypt);
+        return;
+      }
+    }
+    FreeLibrary(bcrypt);
+  }
+
+  // If BCrypt wasn't found, try to use RtlGenRandom. This is available
+  // since XP. For winstorecompat, this call is intercepted and emulated.
+  if (RtlGenRandom(&__stack_chk_guard, sizeof(__stack_chk_guard))) {
+    return;
+  }
+
+  // If RtlGenRandom failed, call rand_s from the CRT. This uses the same
+  // random source as RtlGenRandom above. In the case of msvcrt.dll, the
+  // rand_s function ends up loaded dynamically, and if not found, it tries
+  // to dynamically load RtlGenRandom instead.
   if (rand_s(&ui) == 0) {
     __stack_chk_guard = (void*)(intptr_t)ui;
 #if __SIZEOF_POINTER__ > 4
@@ -31,7 +73,7 @@ static void __cdecl __attribute__((__constructor__)) 
init(void)
     return;
   }
 
-  // If rand_s failed (it shouldn't), hardcode a nonzero default stack guard.
+  // If everything else failed, hardcode a nonzero default stack guard.
 #if __SIZEOF_POINTER__ > 4
   __stack_chk_guard = (void*)0xdeadbeefdeadbeefULL;
 #else
-- 
2.25.1



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to