diff options
author | Pali Rohár <pali@kernel.org> | 2022-04-10 13:58:38 +0200 |
---|---|---|
committer | Martin Mareš <mj@ucw.cz> | 2022-04-15 23:57:52 +0200 |
commit | d0b3d60f84fff7ab9ce99691fcf0db65b416e9ae (patch) | |
tree | f84dbd15cb50055bf089b5e7ef74356450ff42f2 | |
parent | 49b93c5dd9f8ae21533cb0418850a70c12721bf3 (diff) | |
download | pciutils-d0b3d60f84fff7ab9ce99691fcf0db65b416e9ae.tar.gz |
libpci: i386-io-windows.h: Fix error handling for GetProcessImageFileNameW() and GetModuleFileNameExW()
These functions may require buffer which is larger than MAX_PATH (wide)
characters and their error handling is more complicated. Fix it.
-rw-r--r-- | lib/i386-io-windows.h | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/lib/i386-io-windows.h b/lib/i386-io-windows.h index e32ecb2..ac2a55d 100644 --- a/lib/i386-io-windows.h +++ b/lib/i386-io-windows.h @@ -776,10 +776,13 @@ find_and_open_process_for_query(LPCSTR exe_file) EnumProcessesProt MyEnumProcesses; HMODULE kernel32, psapi; UINT prev_error_mode; - WCHAR path[MAX_PATH]; + DWORD partial_retry; + BOOL found_process; DWORD size, length; DWORD *processes; HANDLE process; + LPWSTR path; + DWORD error; DWORD count; DWORD i; @@ -873,11 +876,72 @@ retry: if (!process) continue; + /* + * Set initial buffer size to 256 (wide) characters. + * Final path length on the modern NT-based systems can be also larger. + */ + size = 256; + found_process = FALSE; + partial_retry = 0; + +retry_path: + path = (LPWSTR)LocalAlloc(LPTR, size * sizeof(*path)); + if (!path) + goto end_path; + if (MyGetProcessImageFileNameW) - length = MyGetProcessImageFileNameW(process, path, sizeof(path)/sizeof(*path)); + length = MyGetProcessImageFileNameW(process, path, size); else - length = MyGetModuleFileNameExW(process, NULL, path, sizeof(path)/sizeof(*path)); + length = MyGetModuleFileNameExW(process, NULL, path, size); + + error = GetLastError(); + + /* + * GetModuleFileNameEx() returns zero and signal error ERROR_PARTIAL_COPY + * when remote process is in the middle of updating its module table. + * Sleep 10 ms and try again, max 10 attempts. + */ + if (!MyGetProcessImageFileNameW) + { + if (length == 0 && error == ERROR_PARTIAL_COPY && partial_retry++ < 10) + { + Sleep(10); + goto retry_path; + } + partial_retry = 0; + } + + /* + * When buffer is too small then function GetModuleFileNameEx() returns + * its size argument on older systems (Windows XP) or its size minus + * argument one on new systems (Windows 10) without signalling any error. + * Function GetProcessImageFileNameW() on the other hand returns zero + * value and signals error ERROR_INSUFFICIENT_BUFFER. So in all these + * cases call function again with larger buffer. + */ + + if (MyGetProcessImageFileNameW && length == 0 && error != ERROR_INSUFFICIENT_BUFFER) + goto end_path; + + if ((MyGetProcessImageFileNameW && length == 0) || + (!MyGetProcessImageFileNameW && (length == size || length == size-1))) + { + LocalFree(path); + size *= 2; + goto retry_path; + } + if (length && check_process_name(path, length, exe_file)) + found_process = TRUE; + +end_path: + if (path) + { + LocalFree(path); + path = NULL; + } + + if (found_process) break; CloseHandle(process); |