Browse Source

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

Co-authored-by: Cheng Zhao <[email protected]>
trop[bot] 3 years ago
parent
commit
a2332646fa

+ 1 - 0
patches/node/.patches

@@ -28,3 +28,4 @@ fix_crash_creating_private_key_with_unsupported_algorithm.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

+ 234 - 0
patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch

@@ -0,0 +1,234 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Cheng Zhao <[email protected]>
+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_ */