diff --git a/src/Common/BaseCom.cpp b/src/Common/BaseCom.cpp index 2319576b02..74898a2089 100644 --- a/src/Common/BaseCom.cpp +++ b/src/Common/BaseCom.cpp @@ -21,6 +21,155 @@ using namespace VeraCrypt; +// ======================================================================== +// COM method input validation - whitelists and helper functions +// ======================================================================== + +// Helper: check if IOCTL code is in the allowed list +static BOOL IsIoctlInWhitelist (DWORD ioctl, const DWORD *whitelist, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + if (whitelist[i] == ioctl) + return TRUE; + } + return FALSE; +} + +// Allowed IOCTL codes for CallDriver (VeraCrypt kernel driver IOCTLs) +static const DWORD g_CallDriverIoctlWhitelist[] = { + TC_IOCTL_GET_DRIVER_VERSION, + TC_IOCTL_GET_BOOT_LOADER_VERSION, + TC_IOCTL_MOUNT_VOLUME, + TC_IOCTL_UNMOUNT_VOLUME, + TC_IOCTL_UNMOUNT_ALL_VOLUMES, + TC_IOCTL_GET_MOUNTED_VOLUMES, + TC_IOCTL_GET_VOLUME_PROPERTIES, + TC_IOCTL_GET_DEVICE_REFCOUNT, + TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED, + TC_IOCTL_IS_ANY_VOLUME_MOUNTED, + TC_IOCTL_GET_PASSWORD_CACHE_STATUS, + TC_IOCTL_WIPE_PASSWORD_CACHE, + TC_IOCTL_OPEN_TEST, + TC_IOCTL_GET_DRIVE_PARTITION_INFO, + TC_IOCTL_GET_DRIVE_GEOMETRY, + TC_IOCTL_PROBE_REAL_DRIVE_SIZE, + TC_IOCTL_GET_RESOLVED_SYMLINK, + TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS, + TC_IOCTL_BOOT_ENCRYPTION_SETUP, + TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, + TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT, + TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES, + TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER, + TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME, + TC_IOCTL_GET_PORTABLE_MODE_STATUS, + TC_IOCTL_SET_PORTABLE_MODE_STATUS, + TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING, + TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, + TC_IOCTL_DISK_IS_WRITABLE, + TC_IOCTL_START_DECOY_SYSTEM_WIPE, + TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE, + TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS, + TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT, + TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR, + TC_IOCTL_GET_WARNING_FLAGS, + TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY, + TC_IOCTL_REREAD_DRIVER_CONFIG, + TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG, + VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT, + VC_IOCTL_GET_DRIVE_GEOMETRY_EX, + VC_IOCTL_EMERGENCY_CLEAR_ALL_KEYS, + VC_IOCTL_IS_RAM_ENCRYPTION_ENABLED, + VC_IOCTL_ENCRYPTION_QUEUE_PARAMS, +}; + +// Allowed IOCTL codes for DeviceIoControl (standard disk/storage/filesystem IOCTLs) +static const DWORD g_DeviceIoControlWhitelist[] = { + IOCTL_DISK_GET_DRIVE_GEOMETRY, + IOCTL_DISK_GET_PARTITION_INFO, + IOCTL_DISK_GET_PARTITION_INFO_EX, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + IOCTL_DISK_GET_LENGTH_INFO, + IOCTL_DISK_PERFORMANCE, + IOCTL_STORAGE_GET_DEVICE_NUMBER, + IOCTL_STORAGE_READ_CAPACITY, + IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, + FSCTL_LOCK_VOLUME, + FSCTL_DISMOUNT_VOLUME, + FSCTL_IS_VOLUME_MOUNTED, + FSCTL_GET_NTFS_VOLUME_DATA, + FSCTL_GET_VOLUME_BITMAP, + FSCTL_GET_RETRIEVAL_POINTERS, + FSCTL_MOVE_FILE, + FSCTL_ALLOW_EXTENDED_DASD_IO, + FSCTL_SET_SPARSE, + FSCTL_EXTEND_VOLUME, + FSCTL_SHRINK_VOLUME, +}; + +// Allowed HKLM registry key path prefixes (case-insensitive) +static const wchar_t* g_RegistryKeyPrefixWhitelist[] = { + L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", + L"SYSTEM\\CurrentControlSet\\Services\\VeraCryptSystemFavorites", + L"SYSTEM\\CurrentControlSet\\Control\\Power", + L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power", +}; + +// Helper: check if registry key path matches an allowed prefix (exact or subkey) +static BOOL IsRegistryKeyPathAllowed (const wchar_t *keyPath) +{ + if (!keyPath) + return FALSE; + for (size_t i = 0; i < ARRAYSIZE (g_RegistryKeyPrefixWhitelist); i++) + { + size_t prefixLen = wcslen (g_RegistryKeyPrefixWhitelist[i]); + if (_wcsnicmp (keyPath, g_RegistryKeyPrefixWhitelist[i], prefixLen) == 0) + { + wchar_t nextChar = keyPath[prefixLen]; + if (nextChar == L'\0' || nextChar == L'\\') + return TRUE; + } + } + return FALSE; +} + +// Helper: reject paths containing ".." traversal components +static BOOL ValidatePathNoTraversal (const wchar_t *path) +{ + if (!path) + return FALSE; + if (wcsstr (path, L"..") != NULL) + return FALSE; + return TRUE; +} + +// Helper: case-insensitive check if path contains "veracrypt" substring +static BOOL PathContainsVeraCrypt (const wchar_t *path) +{ + if (!path) + return FALSE; + size_t pathLen = wcslen (path); + if (pathLen < 9) + return FALSE; + for (size_t i = 0; i <= pathLen - 9; i++) + { + if (_wcsnicmp (&path[i], L"veracrypt", 9) == 0) + return TRUE; + } + return FALSE; +} + +// Helper: validate device path format (must start with \\.\ or \\?\) +static BOOL IsValidDevicePath (const wchar_t *path) +{ + if (!path || wcslen (path) < 4) + return FALSE; + return (path[0] == L'\\' && path[1] == L'\\' && (path[2] == L'.' || path[2] == L'?') && path[3] == L'\\'); +} + +// ======================================================================== + + HRESULT CreateElevatedComObject (HWND hwnd, REFGUID guid, REFIID iid, void **ppv) { WCHAR monikerName[1024]; @@ -81,6 +230,9 @@ BOOL ComGetInstanceBase (HWND hWnd, REFCLSID clsid, REFIID iid, void **tcServer) DWORD BaseCom::CallDriver (DWORD ioctl, BSTR input, BSTR *output) { + if (!IsIoctlInWhitelist (ioctl, g_CallDriverIoctlWhitelist, ARRAYSIZE (g_CallDriverIoctlWhitelist))) + return ERROR_ACCESS_DENIED; + try { BootEncryption bootEnc (NULL); @@ -108,6 +260,11 @@ DWORD BaseCom::CallDriver (DWORD ioctl, BSTR input, BSTR *output) DWORD BaseCom::CopyFile (BSTR sourceFile, BSTR destinationFile) { + if (!ValidatePathNoTraversal (sourceFile) || !ValidatePathNoTraversal (destinationFile)) + return ERROR_ACCESS_DENIED; + + if (!PathContainsVeraCrypt (sourceFile) || !PathContainsVeraCrypt (destinationFile)) + return ERROR_ACCESS_DENIED; if (!::CopyFileW (sourceFile, destinationFile, FALSE)) return GetLastError(); @@ -118,6 +275,11 @@ DWORD BaseCom::CopyFile (BSTR sourceFile, BSTR destinationFile) DWORD BaseCom::DeleteFile (BSTR file) { + if (!ValidatePathNoTraversal (file)) + return ERROR_ACCESS_DENIED; + + if (!PathContainsVeraCrypt (file)) + return ERROR_ACCESS_DENIED; if (!::DeleteFileW (file)) return GetLastError(); @@ -134,6 +296,17 @@ BOOL BaseCom::IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly) DWORD BaseCom::ReadWriteFile (BOOL write, BOOL device, BSTR filePath, BSTR *bufferBstr, unsigned __int64 offset, unsigned __int32 size, DWORD *sizeDone) { + if (device) + { + if (!IsValidDevicePath (filePath)) + return ERROR_ACCESS_DENIED; + } + else + { + if (!ValidatePathNoTraversal (filePath)) + return ERROR_ACCESS_DENIED; + } + try { unique_ptr file (device ? new Device (filePath, !write) : new File (filePath, !write)); @@ -172,6 +345,9 @@ DWORD BaseCom::GetFileSize (BSTR filePath, unsigned __int64 *pSize) if (!pSize) return ERROR_INVALID_PARAMETER; + if (!ValidatePathNoTraversal (filePath)) + return ERROR_ACCESS_DENIED; + try { std::wstring path (filePath); @@ -198,6 +374,20 @@ DWORD BaseCom::GetFileSize (BSTR filePath, unsigned __int64 *pSize) DWORD BaseCom::DeviceIoControl (BOOL readOnly, BOOL device, BSTR filePath, DWORD dwIoControlCode, BSTR input, BSTR *output) { + if (!IsIoctlInWhitelist (dwIoControlCode, g_DeviceIoControlWhitelist, ARRAYSIZE (g_DeviceIoControlWhitelist))) + return ERROR_ACCESS_DENIED; + + if (device) + { + if (!IsValidDevicePath (filePath)) + return ERROR_ACCESS_DENIED; + } + else + { + if (!ValidatePathNoTraversal (filePath)) + return ERROR_ACCESS_DENIED; + } + try { unique_ptr file (device ? new Device (filePath, readOnly == TRUE) : new File (filePath, readOnly == TRUE)); @@ -302,6 +492,9 @@ DWORD BaseCom::SetDriverServiceStartType (DWORD startType) DWORD BaseCom::WriteLocalMachineRegistryDwordValue (BSTR keyPath, BSTR valueName, DWORD value) { + if (!IsRegistryKeyPathAllowed (keyPath)) + return ERROR_ACCESS_DENIED; + if (!::WriteLocalMachineRegistryDword (keyPath, valueName, value)) return GetLastError(); @@ -500,5 +693,8 @@ DWORD BaseCom::NotifyService(DWORD dwNotifyCode) DWORD BaseCom::FastFileResize (BSTR filePath, __int64 fileSize) { + if (!ValidatePathNoTraversal (filePath)) + return ERROR_ACCESS_DENIED; + return ::FastResizeFile (filePath, fileSize); } diff --git a/src/Format/FormatCom.cpp b/src/Format/FormatCom.cpp index 738116b09b..5b161d0ab5 100644 --- a/src/Format/FormatCom.cpp +++ b/src/Format/FormatCom.cpp @@ -92,6 +92,8 @@ class TrueCryptFormatCom : public ITrueCryptFormatCom virtual BOOL STDMETHODCALLTYPE FormatNtfs (int driveNo, int clusterSize) { + if (driveNo < 0 || driveNo > 25) + return FALSE; return ::FormatNtfs (driveNo, clusterSize, TRUE); } @@ -134,6 +136,8 @@ class TrueCryptFormatCom : public ITrueCryptFormatCom virtual BOOL STDMETHODCALLTYPE FormatFs (int driveNo, int clusterSize, int fsType) { + if (driveNo < 0 || driveNo > 25) + return FALSE; return ::FormatFs (driveNo, clusterSize, fsType, TRUE); }