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 b17ef873ae #18009

Closes #20853
This commit is contained in:
Viktor Szakats 2026-03-08 15:12:17 +01:00
parent ccba492024
commit 6a6826469d
No known key found for this signature in database
4 changed files with 31 additions and 22 deletions

View File

@ -27,6 +27,7 @@
#include "curlx/version_win32.h" #include "curlx/version_win32.h"
#ifndef CURL_WINDOWS_UWP
/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW) /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */ and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
struct OUR_OSVERSIONINFOEXW { struct OUR_OSVERSIONINFOEXW {
@ -43,6 +44,24 @@ struct OUR_OSVERSIONINFOEXW {
UCHAR wReserved; 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() * curlx_verify_windows_version()
* *
@ -115,24 +134,6 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION | DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; 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) { switch(condition) {
case VERSION_LESS_THAN: case VERSION_LESS_THAN:
majorCondition = VER_LESS; 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 the real version always, so we use the Rtl variant of the function when
possible. Note though the function signatures have underlying fundamental possible. Note though the function signatures have underlying fundamental
types that are the same, the return values are different. */ types that are the same, the return values are different. */
if(pRtlVerifyVersionInfo) if(s_pRtlVerifyVersionInfo)
matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); matched = !s_pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
else else
matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm); 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); cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
dwTypeMask = VER_BUILDNUMBER; dwTypeMask = VER_BUILDNUMBER;
if(pRtlVerifyVersionInfo) if(s_pRtlVerifyVersionInfo)
matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); matched = !s_pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
else else
matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
dwTypeMask, cm); dwTypeMask, cm);

View File

@ -43,6 +43,11 @@ typedef enum {
PLATFORM_WINNT PLATFORM_WINNT
} PlatformIdentifier; } 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 */ /* This is used to verify if we are running on a specific Windows version */
bool curlx_verify_windows_version(const unsigned int majorVersion, bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion, const unsigned int minorVersion,

View File

@ -28,6 +28,7 @@
#include "system_win32.h" #include "system_win32.h"
#include "curl_sspi.h" #include "curl_sspi.h"
#include "curlx/timeval.h" #include "curlx/timeval.h"
#include "curlx/version_win32.h" /* for curlx_verify_windows_init() */
/* Curl_win32_init() performs Win32 global initialization */ /* Curl_win32_init() performs Win32 global initialization */
CURLcode Curl_win32_init(long flags) CURLcode Curl_win32_init(long flags)
@ -77,6 +78,7 @@ CURLcode Curl_win32_init(long flags)
} }
#endif #endif
curlx_verify_windows_init();
curlx_now_init(); curlx_now_init();
return CURLE_OK; return CURLE_OK;
} }

View File

@ -901,6 +901,7 @@ curl_socket_t win32_stdin_read_thread(void)
CURLcode win32_init(void) CURLcode win32_init(void)
{ {
curlx_verify_windows_init();
curlx_now_init(); curlx_now_init();
#ifndef CURL_WINDOWS_UWP #ifndef CURL_WINDOWS_UWP
init_terminal(); init_terminal();