From 4bade83f0813e94dc2b02942740143edfeb43679 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 18 Nov 2020 13:50:20 +0100 Subject: installer: check for KB2921916's setupapi.dll directly Some people might have the right setupapi.dll without actually having installed the quickfix. Search for a distinguishing feature instead. Signed-off-by: Jason A. Donenfeld --- installer/customactions.c | 167 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 23 deletions(-) (limited to 'installer/customactions.c') diff --git a/installer/customactions.c b/installer/customactions.c index b61fd554..2cb629c2 100644 --- a/installer/customactions.c +++ b/installer/customactions.c @@ -122,6 +122,118 @@ out: return ret; } +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define BITOP(a, b, op) ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) + +static char *memmem(const void *h0, size_t k, const void *n0, size_t l) +{ + const unsigned char *n = n0; + const unsigned char *h = h0; + const unsigned char *z = h + k; + size_t i, ip, jp, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = { 0 }; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (i = 0; i < l; i++) + BITOP(byteset, n[i], |=), shift[n[i]] = i + 1; + + /* Compute maximal suffix */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] > n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] < n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip + 1 > ms + 1) + ms = ip; + else + p = p0; + + /* Periodic needle? */ + if (memcmp(n, n + p, ms + 1)) { + mem0 = 0; + p = MAX(ms, l - ms - 1) + 1; + } else + mem0 = l - p; + mem = 0; + + /* Search loop */ + for (;;) { + /* If remainder of haystack is shorter than needle, done */ + if (z - h < l) + return 0; + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l - 1], &)) { + k = l - shift[h[l - 1]]; + if (k) { + if (k < mem) + k = mem; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k = MAX(ms + 1, mem); k < l && n[k] == h[k]; k++) + ; + if (k < l) { + h += k - ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) + ; + if (k <= mem) + return (char *)h; + h += p; + mem = mem0; + } +} + extern NTAPI __declspec(dllimport) void RtlGetNtVersionNumbers(DWORD *MajorVersion, DWORD *MinorVersion, DWORD *BuildNumber); __declspec(dllexport) UINT __stdcall CheckKB2921916(MSIHANDLE installer) @@ -129,39 +241,44 @@ __declspec(dllexport) UINT __stdcall CheckKB2921916(MSIHANDLE installer) bool is_com_initialized = SUCCEEDED(CoInitialize(NULL)); UINT ret = ERROR_SUCCESS; DWORD maj, min, build, len; - HKEY packageKey; - TCHAR subkeyName[0x1000], uiLevel[10]; + TCHAR uiLevel[10]; MSIHANDLE record; + TCHAR setupapi_path[MAX_PATH]; + HANDLE setupapi_handle = INVALID_HANDLE_VALUE; + HANDLE setupapi_filemapping = NULL; + void *setupapi_bytes = NULL; + MEMORY_BASIC_INFORMATION setupapi_meminfo; + static const char setupapi_marker[] = "Signature Hash"; RtlGetNtVersionNumbers(&maj, &min, &build); if (maj != 6 || min != 1) goto out; - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\Packages"), 0, KEY_ENUMERATE_SUB_KEYS, &packageKey); - if (ret != ERROR_SUCCESS) { - log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("Unable to open Component Based Servicing\\Packages registry key")); + ret = ERROR_INSTALL_FAILURE; + if (!GetSystemDirectory(setupapi_path, _countof(setupapi_path))) + goto out; + if (!PathAppend(setupapi_path, TEXT("setupapi.dll"))) + goto out; + setupapi_handle = CreateFile(setupapi_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (setupapi_handle == INVALID_HANDLE_VALUE) + goto out; + setupapi_filemapping = CreateFileMapping(setupapi_handle, NULL, PAGE_READONLY, 0, 0, NULL); + if (!setupapi_filemapping) + goto out; + setupapi_bytes = MapViewOfFile(setupapi_filemapping, FILE_MAP_READ, 0, 0, 0); + if (!setupapi_bytes) + goto out; + if (VirtualQuery(setupapi_bytes, &setupapi_meminfo, sizeof(setupapi_meminfo)) != sizeof(setupapi_meminfo)) + goto out; + if (memmem(setupapi_bytes, setupapi_meminfo.RegionSize, setupapi_marker, strlen(setupapi_marker))) { + ret = ERROR_SUCCESS; goto out; } - for (DWORD i = 0;; ++i) { - len = _countof(subkeyName); - ret = RegEnumKeyEx(packageKey, i, subkeyName, &len, NULL, NULL, NULL, NULL); - if (ret == ERROR_NO_MORE_ITEMS) - break; - if (ret == ERROR_MORE_DATA) - continue; - if (ret != ERROR_SUCCESS) { - log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("Unable to enumerate Component Based Servicing\\Packages registry key")); - goto close_key; - } - if (_tcsstr(subkeyName, TEXT("KB2921916"))) - goto close_key; - } - ret = ERROR_INSTALL_FAILURE; len = _countof(uiLevel); if (MsiGetProperty(installer, TEXT("UILevel"), uiLevel, &len) != ERROR_SUCCESS || _tcstoul(uiLevel, NULL, 10) < INSTALLUILEVEL_BASIC) { log_messagef(installer, LOG_LEVEL_MSIERR, TEXT("Use of WireGuard on Windows 7 requires KB2921916.")); - goto close_key; + goto out; } #ifdef _WIN64 @@ -176,9 +293,13 @@ __declspec(dllexport) UINT __stdcall CheckKB2921916(MSIHANDLE installer) ShellExecute(GetForegroundWindow(), NULL, url, NULL, NULL, SW_SHOWNORMAL); MsiCloseHandle(record); -close_key: - RegCloseKey(packageKey); out: + if (setupapi_bytes) + UnmapViewOfFile(setupapi_bytes); + if (setupapi_filemapping) + CloseHandle(setupapi_filemapping); + if (setupapi_handle != INVALID_HANDLE_VALUE) + CloseHandle(setupapi_handle); if (is_com_initialized) CoUninitialize(); return ret; -- cgit v1.2.3-59-g8ed1b