fix: crash caused by GetHostNameW on Windows 7 (#31804)

This commit is contained in:
Cheng Zhao 2021-11-14 16:39:31 +09:00 committed by GitHub
parent a41898bb9b
commit a6a5ca1db3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 235 additions and 0 deletions

View file

@ -26,3 +26,4 @@ chore_fix_-wimplicit-fallthrough.patch
fix_event_with_invalid_timestamp_in_trace_log.patch
test_fix_test-datetime-change-notify_after_daylight_change.patch
test_add_fixture_trim_option.patch
fix_crash_caused_by_gethostnamew_on_windows_7.patch

View file

@ -0,0 +1,234 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cheng Zhao <zcbenz@gmail.com>
Date: Fri, 12 Nov 2021 17:25:37 +0900
Subject: fix: crash caused by GetHostNameW on Windows 7
Backported from https://github.com/libuv/libuv/pull/3285.
diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
index 88602c7ee8623f16f87398cf3ffd1f71555fc1a0..5ffde08e1aed041c4da679156ed10f7e54bfc386 100644
--- a/deps/uv/src/win/util.c
+++ b/deps/uv/src/win/util.c
@@ -37,6 +37,7 @@
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>
+#include <svcguid.h>
/* clang-format on */
#include <userenv.h>
#include <math.h>
@@ -56,6 +57,10 @@
/* The number of nanoseconds in one second. */
#define UV__NANOSEC 1000000000
+/* Local buffer size for WSAQUERYSETW data inside uv__gethostnamew_nt60
+ sizeof(WSAQUERYSETW) + 512 = 632 bytes to match GetHostNameW behavior */
+#define WSAQ_LOCAL_BUF_LEN (sizeof(WSAQUERYSETW) + 512)
+
/* Max user name length, from iphlpapi.h */
#ifndef UNLEN
# define UNLEN 256
@@ -72,6 +77,11 @@ static CRITICAL_SECTION process_title_lock;
/* Frequency of the high-resolution clock. */
static uint64_t hrtime_frequency_ = 0;
+/* Parameters for WSAQUERYSETW inside uv__gethostnamew_nt60 */
+static GUID guid_host_name = SVCID_HOSTNAME;
+static AFPROTOCOLS af_protocols[2] = { {AF_INET, IPPROTO_UDP},
+ {AF_INET, IPPROTO_TCP} };
+
/*
* One-time initialization code for functionality defined in util.c.
@@ -1663,6 +1673,125 @@ int uv_os_unsetenv(const char* name) {
}
+static int WSAAPI uv__gethostnamew_nt60(PWSTR name, int name_len) {
+ int result_len;
+ int error_code = NO_ERROR;
+
+ /* WSALookupService stuff
+ * Avoid dynamic memory allocation if possible */
+ CHAR local_buf[WSAQ_LOCAL_BUF_LEN];
+ DWORD dwlen = WSAQ_LOCAL_BUF_LEN;
+ WSAQUERYSETW* pwsaq;
+ /* hostname returned from WSALookupService stage */
+ WCHAR* result_name = NULL;
+ /* WSALookupService handle */
+ HANDLE hlookup;
+ /* Fallback to heap allocation if stack buffer is too small */
+ WSAQUERYSETW* heap_data = NULL;
+
+ /* check input */
+ if (name == NULL) {
+ error_code = WSAEFAULT;
+ goto cleanup;
+ }
+
+ /*
+ * Stage 1: Check environment variable
+ * _CLUSTER_NETWORK_NAME_ len == ComputeName(NETBIOS) len.
+ * i.e 15 characters + null.
+ * It overrides the actual hostname, so application can
+ * work when network name and computer name are different
+ */
+ result_len = GetEnvironmentVariableW(L"_CLUSTER_NETWORK_NAME_",
+ name,
+ name_len);
+ if (result_len != 0) {
+ if (result_len > name_len) {
+ error_code = WSAEFAULT;
+ }
+ goto cleanup;
+ }
+
+ /* Stage 2: Do normal lookup through WSALookupServiceLookup */
+ pwsaq = (WSAQUERYSETW*) local_buf;
+ memset(pwsaq, 0, sizeof(*pwsaq));
+ pwsaq->dwSize = sizeof(*pwsaq);
+ pwsaq->lpszServiceInstanceName = NULL;
+ pwsaq->lpServiceClassId = &guid_host_name;
+ pwsaq->dwNameSpace = NS_ALL;
+ pwsaq->lpafpProtocols = &af_protocols[0];
+ pwsaq->dwNumberOfProtocols = 2;
+
+ error_code = WSALookupServiceBeginW(pwsaq, LUP_RETURN_NAME, &hlookup);
+ if (error_code == NO_ERROR) {
+ /* Try stack allocation first */
+ error_code = WSALookupServiceNextW(hlookup, 0, &dwlen, pwsaq);
+ if (error_code == NO_ERROR) {
+ result_name = pwsaq->lpszServiceInstanceName;
+ } else {
+ error_code = WSAGetLastError();
+
+ if (error_code == WSAEFAULT) {
+ /* Should never happen */
+ assert(sizeof(CHAR) * dwlen >= sizeof(WSAQUERYSETW));
+
+ /* Fallback to the heap allocation */
+ heap_data = uv__malloc(sizeof(CHAR) * (size_t) dwlen);
+ if (heap_data != NULL) {
+ error_code = WSALookupServiceNextW(hlookup, 0, &dwlen, heap_data);
+ if (error_code == NO_ERROR) {
+ result_name = heap_data->lpszServiceInstanceName;
+ } else {
+ error_code = WSAGetLastError();
+ }
+ } else {
+ error_code = WSA_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+
+ WSALookupServiceEnd(hlookup);
+
+ if (error_code != NO_ERROR) {
+ WSASetLastError(error_code);
+ }
+ }
+
+ if (result_name != NULL) {
+ size_t wlen = wcslen(result_name) + 1;
+
+ if (wlen <= (size_t) name_len) {
+ wmemcpy(name, result_name, wlen);
+ } else {
+ error_code = WSAEFAULT;
+ }
+ goto cleanup;
+ }
+
+ /* Stage 3: If WSALookupServiceLookup fails, fallback to GetComputerName */
+ result_len = name_len;
+ /* Reset error code */
+ error_code = NO_ERROR;
+
+ if (GetComputerNameW(name, (PDWORD)&result_len) == FALSE) {
+ error_code = WSAENETDOWN;
+ if (result_len >= name_len) {
+ error_code = WSAEFAULT;
+ }
+ }
+
+cleanup:
+ uv__free(heap_data);
+
+ if (error_code == NO_ERROR) {
+ return NO_ERROR;
+ } else {
+ WSASetLastError(error_code);
+ return SOCKET_ERROR;
+ }
+}
+
+
int uv_os_gethostname(char* buffer, size_t* size) {
WCHAR buf[UV_MAXHOSTNAMESIZE];
size_t len;
@@ -1674,7 +1803,9 @@ int uv_os_gethostname(char* buffer, size_t* size) {
uv__once_init(); /* Initialize winsock */
- if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
+ sGetHostNameW gethostnamew =
+ pGetHostNameW == NULL ? uv__gethostnamew_nt60 : pGetHostNameW;
+ if (gethostnamew(buf, UV_MAXHOSTNAMESIZE) != 0)
return uv_translate_sys_error(WSAGetLastError());
convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c
index bb86ec8ceac8ba3fccd02b292aca7ddfab38e187..9d6effb10ddd1801f7411ee71a70575b7072ab7d 100644
--- a/deps/uv/src/win/winapi.c
+++ b/deps/uv/src/win/winapi.c
@@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
/* User32.dll function pointer */
sSetWinEventHook pSetWinEventHook;
+/* ws2_32.dll function pointer */
+sGetHostNameW pGetHostNameW;
void uv_winapi_init(void) {
HMODULE ntdll_module;
HMODULE powrprof_module;
HMODULE user32_module;
HMODULE kernel32_module;
+ HMODULE ws2_32_module;;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
@@ -134,4 +137,10 @@ void uv_winapi_init(void) {
pSetWinEventHook = (sSetWinEventHook)
GetProcAddress(user32_module, "SetWinEventHook");
}
+
+ ws2_32_module = LoadLibraryA("ws2_32.dll");
+ if (ws2_32_module != NULL) {
+ pGetHostNameW = (sGetHostNameW)
+ GetProcAddress(ws2_32_module, "GetHostNameW");
+ }
}
diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h
index 0b66b5634bca88cec65b1bf0c0193986f5ddd542..5951717ab9e21db274f956c44410cc03c1617eaf 100644
--- a/deps/uv/src/win/winapi.h
+++ b/deps/uv/src/win/winapi.h
@@ -4739,6 +4739,11 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS {
# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
#endif
+/* From winsock2.h */
+typedef int (WSAAPI *sGetHostNameW)
+ (PWSTR name,
+ int namelen);
+
/* Ntdll function pointers */
extern sRtlGetVersion pRtlGetVersion;
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
@@ -4759,4 +4764,7 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
/* User32.dll function pointer */
extern sSetWinEventHook pSetWinEventHook;
+/* ws2_32.dll function pointer */
+extern sGetHostNameW pGetHostNameW;
+
#endif /* UV_WIN_WINAPI_H_ */