X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Fi386-io-windows.h;h=fd1a54e24b73e2a4664787936d75557d2eb2064d;hb=327b6e8a1660e1c937b7987fa31f972af393521b;hp=ca8b3bb5b901263dfbfcad4b746f9de39f6dc852;hpb=b8fbb6f00e1f6b495dc826009f1494835e56a2c7;p=pciutils.git diff --git a/lib/i386-io-windows.h b/lib/i386-io-windows.h index ca8b3bb..fd1a54e 100644 --- a/lib/i386-io-windows.h +++ b/lib/i386-io-windows.h @@ -5,7 +5,9 @@ * Copyright (c) 2006 Martin Mares * Copyright (c) 2021 Pali Rohár * - * Can be freely distributed and used under the terms of the GNU GPL. + * Can be freely distributed and used under the terms of the GNU GPL v2+ + * + * SPDX-License-Identifier: GPL-2.0-or-later */ #include @@ -35,12 +37,11 @@ #define _inp(x) __inbyte(x) #define _inpw(x) __inword(x) #define _inpd(x) __indword(x) -#elif defined(__CRTDLL__) +#elif defined(__CRTDLL__) || (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x400) /* - * Old CRTDLL library does not provide I/O port functions. Even it is the oldest - * CRT library it exists also in 64-bit variant. Implement I/O port functions - * via inline assembly just for 32-bit mode as 64-bit mode uses above - * header. + * Old 32-bit CRTDLL library and pre-4.00 MSVCRT library do not provide I/O + * port functions. As these libraries exist only in 32-bit mode variant, + * implement I/O port functions via 32-bit inline assembly. */ static inline int _outp(unsigned short port, int databyte) { @@ -108,16 +109,13 @@ unsigned long _inpd(unsigned short port); * function conflicts with some MSVC intrinsic. * MSVC supports inline assembly via __asm keyword in 32-bit mode only. * GCC version 4.9.0 and higher provides __builtin_ia32_readeflags_uXX() - * builtin for XX-mode. + * builtin for XX-mode. This builtin is also available as __readeflags() + * function indirectly via header file. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500 || (_MSC_VER >= 1400 && defined(__BUILDMACHINE__))) #pragma intrinsic(__readeflags) #elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || (__GNUC__ > 4)) -#ifdef __x86_64__ -#define __readeflags() __builtin_ia32_readeflags_u64() -#else -#define __readeflags() __builtin_ia32_readeflags_u32() -#endif +#include #elif defined(_MSC_VER) && defined(_M_IX86) static inline unsigned int __readeflags(void) @@ -777,10 +775,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; @@ -874,11 +875,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); @@ -1031,6 +1093,7 @@ SetProcessUserModeIOPL(VOID) impersonate_privilege_enabled = FALSE; revert_to_old_token = FALSE; lsass_token = NULL; + old_token = NULL; /* Fast path when ProcessUserModeIOPL was already called. */ if (read_iopl() == 3) @@ -1282,7 +1345,8 @@ intel_setup_io(struct pci_access *a) /* On NT-based systems issue ProcessUserModeIOPL syscall which changes IOPL to 3. */ if (!SetProcessUserModeIOPL()) { - a->warning("NT ProcessUserModeIOPL call failed with error: %lu.", (unsigned long int)GetLastError()); + DWORD error = GetLastError(); + a->debug("NT ProcessUserModeIOPL call failed: %s.", error == ERROR_INVALID_FUNCTION ? "Not Implemented" : error == ERROR_PRIVILEGE_NOT_HELD ? "Access Denied" : "Operation Failed"); return 0; } @@ -1290,7 +1354,7 @@ intel_setup_io(struct pci_access *a) return 1; } -static inline int +static inline void intel_cleanup_io(struct pci_access *a UNUSED) { /* @@ -1298,7 +1362,6 @@ intel_cleanup_io(struct pci_access *a UNUSED) * systems ProcessUserModeIOPL permanently changes IOPL to 3 for the current * NT process, no revert for current process is possible. */ - return 1; } static inline void intel_io_lock(void)