From 6a6826469dded347e62f41cc917d3ac77ff76faa Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 8 Mar 2026 15:12:17 +0100 Subject: [PATCH] windows: determine `RtlVerifyVersionInfo` address on global init Instead of the first internal call to `curlx_verify_windows_version()`. To avoid the chance of a race, potentially resulting in initializing this address twice. AFAICT it could not cause an issue before this patch. Reported by Codex Security Follow-up to b17ef873ae2151263667f4b6fb6abfe337e687dc #18009 Closes #20853 --- lib/curlx/version_win32.c | 45 ++++++++++++++++++++------------------- lib/curlx/version_win32.h | 5 +++++ lib/system_win32.c | 2 ++ src/tool_doswin.c | 1 + 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/curlx/version_win32.c b/lib/curlx/version_win32.c index 1229c39317..296a38d924 100644 --- a/lib/curlx/version_win32.c +++ b/lib/curlx/version_win32.c @@ -27,6 +27,7 @@ #include "curlx/version_win32.h" +#ifndef CURL_WINDOWS_UWP /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW) and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */ struct OUR_OSVERSIONINFOEXW { @@ -43,6 +44,24 @@ struct OUR_OSVERSIONINFOEXW { UCHAR wReserved; }; +typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN) + (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG); +static RTLVERIFYVERSIONINFO_FN s_pRtlVerifyVersionInfo; + +void curlx_verify_windows_init(void) +{ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif + s_pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, + GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlVerifyVersionInfo")); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif +} +#endif /* !CURL_WINDOWS_UWP */ + /* * curlx_verify_windows_version() * @@ -115,24 +134,6 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; - typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN) - (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG); - static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo; - static bool onetime = TRUE; /* safe because first call is during init */ - - if(onetime) { -#if defined(__clang__) && __clang_major__ >= 16 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-function-type-strict" -#endif - pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, - GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlVerifyVersionInfo")); -#if defined(__clang__) && __clang_major__ >= 16 -#pragma clang diagnostic pop -#endif - onetime = FALSE; - } - switch(condition) { case VERSION_LESS_THAN: majorCondition = VER_LESS; @@ -203,8 +204,8 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, the real version always, so we use the Rtl variant of the function when possible. Note though the function signatures have underlying fundamental types that are the same, the return values are different. */ - if(pRtlVerifyVersionInfo) - matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); + if(s_pRtlVerifyVersionInfo) + matched = !s_pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); else matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm); @@ -222,8 +223,8 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition); dwTypeMask = VER_BUILDNUMBER; - if(pRtlVerifyVersionInfo) - matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); + if(s_pRtlVerifyVersionInfo) + matched = !s_pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); else matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm); diff --git a/lib/curlx/version_win32.h b/lib/curlx/version_win32.h index 569626afc8..c4a1c0f758 100644 --- a/lib/curlx/version_win32.h +++ b/lib/curlx/version_win32.h @@ -43,6 +43,11 @@ typedef enum { PLATFORM_WINNT } PlatformIdentifier; +#ifdef CURL_WINDOWS_UWP +#define curlx_verify_windows_init() Curl_nop_stmt +#else +void curlx_verify_windows_init(void); +#endif /* This is used to verify if we are running on a specific Windows version */ bool curlx_verify_windows_version(const unsigned int majorVersion, const unsigned int minorVersion, diff --git a/lib/system_win32.c b/lib/system_win32.c index f91a81a113..1b052357b5 100644 --- a/lib/system_win32.c +++ b/lib/system_win32.c @@ -28,6 +28,7 @@ #include "system_win32.h" #include "curl_sspi.h" #include "curlx/timeval.h" +#include "curlx/version_win32.h" /* for curlx_verify_windows_init() */ /* Curl_win32_init() performs Win32 global initialization */ CURLcode Curl_win32_init(long flags) @@ -77,6 +78,7 @@ CURLcode Curl_win32_init(long flags) } #endif + curlx_verify_windows_init(); curlx_now_init(); return CURLE_OK; } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index c56a41d081..ad0386555d 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -901,6 +901,7 @@ curl_socket_t win32_stdin_read_thread(void) CURLcode win32_init(void) { + curlx_verify_windows_init(); curlx_now_init(); #ifndef CURL_WINDOWS_UWP init_terminal();