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
