From 3021745f67164c2a19cafc0ed1eff7d35830f662 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Thu, 20 Jul 2017 00:52:03 +0200 Subject: [PATCH] Windows: better workaround for cases where ERROR_INVALID_PARAMETER is returned during system encryption which is due to 4096-bytes alignment of disk. --- src/Common/BootEncryption.cpp | 140 +++++++++++++++++++++++++--------- src/Common/BootEncryption.h | 3 +- 2 files changed, 108 insertions(+), 35 deletions(-) diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp index 40e9e77b..f0fb414d 100644 --- a/src/Common/BootEncryption.cpp +++ b/src/Common/BootEncryption.cpp @@ -474,12 +474,12 @@ namespace VeraCrypt #endif // SETUP - File::File (wstring path, bool readOnly, bool create, bool useNormalAttributes) : Elevated (false), FileOpen (false), ReadOnly (readOnly), LastError(0) + File::File (wstring path, bool readOnly, bool create) : Elevated (false), FileOpen (false), ReadOnly (readOnly), LastError(0) { Handle = CreateFile (path.c_str(), readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING, - useNormalAttributes? FILE_ATTRIBUTE_NORMAL : (FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH), NULL); + FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL); if (Handle != INVALID_HANDLE_VALUE) { @@ -530,7 +530,45 @@ namespace VeraCrypt return bytesRead; } - throw_sys_if (!ReadFile (Handle, buffer, size, &bytesRead, NULL)); + if (!ReadFile (Handle, buffer, size, &bytesRead, NULL)) + { + DWORD dwLastError = GetLastError(); + if ((dwLastError == ERROR_INVALID_PARAMETER) && IsDevice && (size % 4096)) + { + DWORD remainingSize = (size % 4096); + DWORD alignedSize = size - remainingSize; + LARGE_INTEGER offset; + + if (alignedSize) + { + if (ReadFile (Handle, buffer, alignedSize, &bytesRead, NULL)) + { + if (bytesRead < alignedSize) + return bytesRead; + + buffer += alignedSize; + size -= alignedSize; + } + else + throw SystemException (SRC_POS); + } + + + if (ReadFile (Handle, ReadBuffer, 4096, &bytesRead, NULL)) + { + DWORD effectiveSize = min (bytesRead, remainingSize); + memcpy (buffer, ReadBuffer, effectiveSize); + offset.QuadPart = - ((LONGLONG) bytesRead) + (LONGLONG) effectiveSize; + SetFilePointerEx (Handle, offset, NULL, FILE_CURRENT); + return alignedSize + effectiveSize; + } + else + throw SystemException (SRC_POS); + } + else + throw SystemException (SRC_POS); + } + return bytesRead; } @@ -600,7 +638,63 @@ namespace VeraCrypt } else { - throw_sys_if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL) || bytesWritten != size); + if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL)) + { + DWORD dwLastError = GetLastError (); + if ((ERROR_INVALID_PARAMETER == dwLastError) && IsDevice && !ReadOnly && (size % 4096)) + { + bool bSuccess = false; + DWORD remainingSize = (size % 4096); + DWORD alignedSize = size - remainingSize; + DWORD bytesRead = 0; + bytesWritten = 0; + if (alignedSize) + { + if (WriteFile (Handle, buffer, alignedSize, &bytesWritten, NULL)) + { + throw_sys_if (bytesWritten != alignedSize); + buffer += alignedSize; + size -= alignedSize; + } + else + { + bytesWritten = 0; + dwLastError = GetLastError (); + } + } + + if (!alignedSize || (alignedSize && bytesWritten)) + { + LARGE_INTEGER offset; + + throw_sys_if (!ReadFile (Handle, ReadBuffer, 4096, &bytesRead, NULL) || (bytesRead != 4096)); + offset.QuadPart = -4096; + throw_sys_if (!SetFilePointerEx (Handle, offset, NULL, FILE_CURRENT)); + + memcpy (ReadBuffer, buffer, remainingSize); + + if (WriteFile (Handle, ReadBuffer, 4096, &bytesWritten, NULL)) + { + throw_sys_if (bytesWritten != 4096); + bSuccess = true; + } + else + { + dwLastError = GetLastError (); + } + } + + if (!bSuccess) + { + SetLastError (dwLastError); + throw SystemException (SRC_POS); + } + } + else + throw SystemException (SRC_POS); + } + else + throw_sys_if (bytesWritten != size); } } catch (SystemException &e) @@ -2134,21 +2228,10 @@ namespace VeraCrypt memcpy (fileContent.data(), "\xEF\xBB\xBF", 3); memcpy (&fileContent[dwOffset], pbData, dwDataLen); - try - { - File f(pathESP + szFilePath, false, true); - f.Write(fileContent.data(), dwSize); - f.Close(); - } - catch (SystemException &e) - { - if (e.ErrorCode != ERROR_INVALID_PARAMETER) - throw; - // try again with normal attributes - File f(pathESP + szFilePath, false, true, true); - f.Write(fileContent.data(), dwSize); - f.Close(); - } + File f(pathESP + szFilePath, false, true); + f.Write(fileContent.data(), dwSize); + f.Close(); + } EfiBoot::EfiBoot() { @@ -2436,22 +2519,11 @@ namespace VeraCrypt void EfiBoot::SaveFile(const wchar_t* name, byte* data, DWORD size) { wstring path = EfiBootPartPath; path += name; - try - { - File f(path, false, true); - f.Write(data, size); - f.Close(); - } - catch (SystemException &e) - { - if (e.ErrorCode != ERROR_INVALID_PARAMETER) - throw; - // try again with normal attributes - File f(path, false, true, true); - f.Write(data, size); - f.Close(); - } + File f(path, false, true); + f.Write(data, size); + f.Close(); + } void EfiBoot::GetFileSize(const wchar_t* name, unsigned __int64& size) { diff --git a/src/Common/BootEncryption.h b/src/Common/BootEncryption.h index 0f8e993b..f63ec541 100644 --- a/src/Common/BootEncryption.h +++ b/src/Common/BootEncryption.h @@ -37,7 +37,7 @@ namespace VeraCrypt { public: File () : Elevated (false), FileOpen (false), ReadOnly (false), FilePointerPosition(0), Handle(INVALID_HANDLE_VALUE), IsDevice(false), LastError(0) { } - File (wstring path,bool readOnly = false, bool create = false, bool useNormalAttributes = false); + File (wstring path,bool readOnly = false, bool create = false); virtual ~File () { Close(); } void CheckOpened (const char* srcPos) { if (!FileOpen) { SetLastError (LastError); throw SystemException (srcPos);} } @@ -58,6 +58,7 @@ namespace VeraCrypt bool IsDevice; wstring Path; DWORD LastError; + BYTE ReadBuffer[4096]; };