X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=inline;f=lib%2Fi386-io-windows.h;h=fd4030d9e7125942c58d4f12fe45ea39b99b0e81;hb=7d23054d18402b1891343f090d3cd37d7e83c82f;hp=9cd9cd95498481297b7f7dee6d17b05f6338f245;hpb=addd89fe60d62faa134e361f562a2fed8e74d91a;p=pciutils.git diff --git a/lib/i386-io-windows.h b/lib/i386-io-windows.h index 9cd9cd9..fd4030d 100644 --- a/lib/i386-io-windows.h +++ b/lib/i386-io-windows.h @@ -5,98 +5,15 @@ * 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 #include #include -#ifdef _MSC_VER -/* MSVC compiler provides I/O port intrinsics for both 32 and 64-bit modes. */ -#pragma intrinsic(_outp) -#pragma intrinsic(_outpw) -#pragma intrinsic(_outpd) -#pragma intrinsic(_inp) -#pragma intrinsic(_inpw) -#pragma intrinsic(_inpd) -#elif defined(_WIN64) || defined(_UCRT) -/* - * For other compilers I/O port intrinsics are available in header - * file either as inline/external functions or macros. Beware that - * names are different than MSVC intrinsics names and glibc function names. - * Usage of is also the prefered way for 64-bit mode or when using - * new UCRT library. - */ -#include -#define _outp(x,y) __outbyte(x,y) -#define _outpw(x,y) __outword(x,y) -#define _outpd(x,y) __outdword(x,y) -#define _inp(x) __inbyte(x) -#define _inpw(x) __inword(x) -#define _inpd(x) __indword(x) -#elif defined(__CRTDLL__) -/* - * Old 32-bit CRTDLL library does not provide I/O port functions. As this - * library exists 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) -{ - asm volatile ("outb %b0, %w1" : : "a" (databyte), "Nd" (port)); - return databyte; -} -static inline unsigned short _outpw(unsigned short port, unsigned short dataword) -{ - asm volatile ("outw %w0, %w1" : : "a" (dataword), "Nd" (port)); - return dataword; -} -static inline unsigned long _outpd(unsigned short port, unsigned long dataword) -{ - asm volatile ("outl %0, %w1" : : "a" (dataword), "Nd" (port)); - return dataword; -} -static inline int _inp(unsigned short port) -{ - unsigned char ret; - asm volatile ("inb %w1, %0" : "=a" (ret) : "Nd" (port)); - return ret; -} -static inline unsigned short _inpw(unsigned short port) -{ - unsigned short ret; - asm volatile ("inw %w1, %0" : "=a" (ret) : "Nd" (port)); - return ret; -} -static inline unsigned long _inpd(unsigned short port) -{ - unsigned long ret; - asm volatile ("inl %w1, %0" : "=a" (ret) : "Nd" (port)); - return ret; -} -#elif !defined(__GNUC__) -/* - * Old 32-bit MSVCRT (non-UCRT) library provides I/O port functions. Function - * prototypes are defined in header file but they are missing in - * some MinGW toolchains. So for GCC compiler define them manually. - */ -#include -#else -int _outp(unsigned short port, int databyte); -unsigned short _outpw(unsigned short port, unsigned short dataword); -unsigned long _outpd(unsigned short port, unsigned long dataword); -int _inp(unsigned short port); -unsigned short _inpw(unsigned short port); -unsigned long _inpd(unsigned short port); -#endif - -#define outb(x,y) _outp(y,x) -#define outw(x,y) _outpw(y,x) -#define outl(x,y) _outpd(y,x) - -#define inb(x) _inp(x) -#define inw(x) _inpw(x) -#define inl(x) _inpd(x) +#include "i386-io-access.h" /* * Define __readeflags() for MSVC and GCC compilers. @@ -107,16 +24,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) @@ -593,12 +507,14 @@ grant_process_token_dacl_permissions(HANDLE process, DWORD permissions, HANDLE * if (MySetSecurityInfo(*token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS) { + LocalFree(new_dacl); LocalFree(*security_descriptor); LocalFree(owner); CloseHandle(*token); return FALSE; } + LocalFree(new_dacl); LocalFree(owner); return TRUE; } @@ -776,10 +692,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 +792,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); @@ -1080,7 +1060,7 @@ SetProcessUserModeIOPL(VOID) */ if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &luid_tcb_privilege)) - goto err_not_implemented; + goto err_privilege_not_held; /* * If the current thread has already Tcb privilege enabled then there @@ -1282,7 +1262,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; }