From 4617ba786d51dae3fa6364c9d1ff359f06d41097 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 20 Jul 2017 17:42:53 +0100 Subject: [PATCH] [process] add a timeout for the process search * The process search appears to be blocking on some platform, and we also don't want users to have to wait too long on format startup * Also update the update check for Windows XP SSL errors --- src/drive.c | 4 +-- src/net.c | 6 +++- src/process.c | 81 ++++++++++++++++++++++++++++++++++++--------------- src/rufus.c | 4 +-- src/rufus.h | 2 +- src/rufus.rc | 10 +++---- 6 files changed, 72 insertions(+), 35 deletions(-) diff --git a/src/drive.c b/src/drive.c index 3fd7b0c6..6620b194 100644 --- a/src/drive.c +++ b/src/drive.c @@ -153,7 +153,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr bWriteShare = TRUE; // Try to report the process that is locking the drive // We also use bit 6 as a flag to indicate that SearchProcess was called. - access_mask = SearchProcess(DevPath, TRUE, TRUE, FALSE) | 0x40; + access_mask = SearchProcess(DevPath, 5000, TRUE, TRUE, FALSE) | 0x40; } Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES); } @@ -184,7 +184,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr uprintf("Could not lock access to %s: %s", Path, WindowsErrorString()); // See if we can report the processes are accessing the drive if (!IS_ERROR(FormatStatus) && (access_mask == 0)) - access_mask = SearchProcess(DevPath, TRUE, TRUE, FALSE); + access_mask = SearchProcess(DevPath, 5000, TRUE, TRUE, FALSE); // Try to continue if the only access rights we saw were for read-only if ((access_mask & 0x07) != 0x01) safe_closehandle(hDrive); diff --git a/src/net.c b/src/net.c index 57a13ff5..418814ba 100644 --- a/src/net.c +++ b/src/net.c @@ -175,6 +175,8 @@ const char* WinInetErrorString(void) return "The header could not be added because it already exists."; case ERROR_HTTP_REDIRECT_FAILED: return "The redirection failed because either the scheme changed or all attempts made to redirect failed."; + case ERROR_INTERNET_SECURITY_CHANNEL_ERROR: + return "This system's SSL library is too old to be able to access this website."; case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: return "Client Authentication certificate needed"; case ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT: @@ -512,8 +514,10 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS| INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_HYPERLINK| ((UrlParts.nScheme == INTERNET_SCHEME_HTTPS)?INTERNET_FLAG_SECURE:0), (DWORD_PTR)NULL); - if ((hRequest == NULL) || (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0))) + if ((hRequest == NULL) || (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0))) { + uprintf("Unable to send request: %s", WinInetErrorString()); goto out; + } // Ensure that we get a text file dwSize = sizeof(dwStatus); diff --git a/src/process.c b/src/process.c index 32795d32..a20dc191 100644 --- a/src/process.c +++ b/src/process.c @@ -52,6 +52,9 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtClose, (HANDLE)); PF_TYPE_DECL(WINAPI, BOOL, QueryFullProcessImageNameW, (HANDLE, DWORD, LPWSTR, PDWORD)); static PVOID PhHeapHandle = NULL; +static char* _HandleName; +static BOOL _bPartialMatch, _bIgnoreSelf, _bQuiet; +static BYTE access_mask; extern StrArray BlockingProcess; /* @@ -307,18 +310,8 @@ NTSTATUS PhQueryProcessesUsingVolumeOrFile(HANDLE VolumeOrFileHandle, return status; } -/** - * Search all the processes and list the ones that have a specific handle open. - * - * \param HandleName The name of the handle to look for. - * \param bPartialMatch Whether partial matches should be allowed. - * \param bIgnoreSelf Whether the current process should be listed. - * \param bQuiet Prints minimal output. - * - * \return a byte containing the cummulated access rights (f----xwr) from all the handles found - * with bit 7 ('f') also set if at least one process was found. - */ -BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet) + +static DWORD WINAPI SearchProcessThread(LPVOID param) { const char *access_rights_str[8] = { "n", "r", "w", "rw", "x", "rx", "wx", "rwx" }; char tmp[MAX_PATH]; @@ -333,9 +326,8 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL WCHAR *wHandleName = NULL; HANDLE dupHandle = NULL; HANDLE processHandle = NULL; - BOOLEAN bFound = FALSE, bGotExePath, verbose = !bQuiet; + BOOLEAN bFound = FALSE, bGotExePath, verbose = !_bQuiet; ULONG access_rights = 0; - BYTE access_mask = 0; DWORD size; char exe_path[MAX_PATH] = { 0 }; wchar_t wexe_path[MAX_PATH]; @@ -361,7 +353,7 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL pid[0] = (ULONG_PTR)0; cur_pid = 1; - wHandleName = utf8_to_wchar(HandleName); + wHandleName = utf8_to_wchar(_HandleName); wHandleNameLen = (USHORT)wcslen(wHandleName); bufferSize = 0x200; @@ -435,7 +427,7 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL // Now duplicate this handle onto our own process, so that we can access its properties if (processHandle == NtCurrentProcess()) { - if (bIgnoreSelf) + if (_bIgnoreSelf) continue; dupHandle = (HANDLE)handleInfo->HandleValue; } else { @@ -471,11 +463,11 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL } // Don't bother comparing if we are looking for full match and the length is different - if ((!bPartialMatch) && (wHandleNameLen != buffer->Name.Length)) + if ((!_bPartialMatch) && (wHandleNameLen != buffer->Name.Length)) continue; // Likewise, if we are looking for a partial match and the current length is smaller - if ((bPartialMatch) && (wHandleNameLen > buffer->Name.Length)) + if ((_bPartialMatch) && (wHandleNameLen > buffer->Name.Length)) continue; // Match against our target string @@ -494,7 +486,7 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL // If this is the very first process we find, print a header if (exe_path[0] == 0) - vuprintf("WARNING: The following process(es) or service(s) are accessing %s:", HandleName); + vuprintf("WARNING: The following process(es) or service(s) are accessing %s:", _HandleName); // First, we try to get the executable path using GetModuleFileNameEx bGotExePath = (GetModuleFileNameExU(processHandle, 0, exe_path, MAX_PATH - 1) != 0); @@ -508,10 +500,12 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL wchar_to_utf8_no_alloc(wexe_path, exe_path, sizeof(exe_path)); } - // Still nothing? Try GetProcessImageFileName (but don't bother about Unicode) - // Note that GetProcessImageFileName uses '\Device\Harddisk#\Partition#' instead drive letters - if (!bGotExePath) - bGotExePath = (GetProcessImageFileNameA(processHandle, exe_path, MAX_PATH) != 0); + // Still nothing? Try GetProcessImageFileName. Note that GetProcessImageFileName uses + // '\Device\Harddisk#\Partition#\' instead drive letters + if (!bGotExePath) { + if (bGotExePath = (GetProcessImageFileNameW(processHandle, wexe_path, MAX_PATH) != 0)) + wchar_to_utf8_no_alloc(wexe_path, exe_path, sizeof(exe_path)); + } // Complete failure => Just craft a default process name that includes the PID if (!bGotExePath) { @@ -524,12 +518,51 @@ out: if (exe_path[0] != 0) vuprintf("You should close these applications before attempting to reformat the drive."); else - vuprintf("NOTE: Could not identify the process(es) or service(s) accessing %s", HandleName); + vuprintf("NOTE: Could not identify the process(es) or service(s) accessing %s", _HandleName); free(wHandleName); PhFree(buffer); PhFree(handles); PhDestroyHeap(); + ExitThread((DWORD)access_mask); +} + +/** + * Search all the processes and list the ones that have a specific handle open. + * + * \param HandleName The name of the handle to look for. + * \param dwTimeOut The maximum amounf of time (ms) that may be spent searching + * \param bPartialMatch Whether partial matches should be allowed. + * \param bIgnoreSelf Whether the current process should be listed. + * \param bQuiet Prints minimal output. + * + * \return a byte containing the cummulated access rights (f----xwr) from all the handles found + * with bit 7 ('f') also set if at least one process was found. + */ +BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet) +{ + HANDLE handle; + DWORD dw = 0; + + _HandleName = HandleName; + _bPartialMatch = bPartialMatch; + _bIgnoreSelf = bIgnoreSelf; + _bQuiet = bQuiet; + access_mask = 0; + + handle = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL); + if (handle == NULL) { + uprintf("Unable to create process search thread"); + return 0x00; + } + dw = WaitForSingleObject(handle, dwTimeOut); + if (dw == WAIT_TIMEOUT) { + // Timeout - kill the thread + TerminateThread(handle, 0); + uprintf("Warning: Killed process search thread"); + } else if (dw != WAIT_OBJECT_0) { + uprintf("Failed to wait for process search thread: %s", WindowsErrorString()); + } return access_mask; } diff --git a/src/rufus.c b/src/rufus.c index 562a76db..6dbff4de 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -2172,7 +2172,7 @@ static BOOL CheckDriveAccess(void) // Search for any blocking processes against the physical drive PhysicalPath = GetPhysicalName(DeviceNum); QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath)); - access_mask = SearchProcess(DevPath, TRUE, TRUE, TRUE); + access_mask = SearchProcess(DevPath, 2000, TRUE, TRUE, TRUE); if (access_mask != 0) { bProceed = FALSE; uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]); @@ -2187,7 +2187,7 @@ static BOOL CheckDriveAccess(void) drive_name[0] = drive_letter[i]; if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) { StrArrayClear(&BlockingProcess); - access_mask = SearchProcess(DevPath, TRUE, TRUE, TRUE); + access_mask = SearchProcess(DevPath, 2000, TRUE, TRUE, TRUE); // Ignore if all we have is read-only if ((access_mask & 0x06) || (access_mask == 0x80)) { bProceed = FALSE; diff --git a/src/rufus.h b/src/rufus.h index af7465b9..64873f1d 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -497,7 +497,7 @@ extern char* GetCurrentMUI(void); extern char* GetMuiString(char* szModuleName, UINT uID); extern BOOL SetFormatPromptHook(void); extern void ClrFormatPromptHook(void); -extern BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet); +extern BYTE SearchProcess(char* HandleName, DWORD dwTimeout, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet); extern BOOL EnablePrivileges(void); extern void FlashTaskbar(HANDLE handle); diff --git a/src/rufus.rc b/src/rufus.rc index e788ef9e..de9f0b13 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.16.1145" +CAPTION "Rufus 2.16.1146" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -366,8 +366,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,16,1145,0 - PRODUCTVERSION 2,16,1145,0 + FILEVERSION 2,16,1146,0 + PRODUCTVERSION 2,16,1146,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -384,13 +384,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.16.1145" + VALUE "FileVersion", "2.16.1146" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.16.1145" + VALUE "ProductVersion", "2.16.1146" END END BLOCK "VarFileInfo"