mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-08-30 12:47:02 +00:00
OpenBSD device length detection was returning the raw disk sector count from DIOCGPDINFO directly. That value is not bytes and it describes the physical/default disk label, which caused VeraCrypt to expose an incorrectly sized FUSE backing image through vnd for device-hosted volumes. Use the current disklabel from DIOCGDINFO, derive the opened partition from the device minor number, and return the selected partition size in bytes. Keep the raw c partition on the whole-disk path by using DL_GETDSIZE there. Also reject sector-misaligned device-hosted sizes during volume creation so new malformed OpenBSD device-hosted volumes are not created. Do not reject existing malformed headers at mount time, so users can still mount old OpenBSD-created volumes for recovery. Refs #1589. Refs #1593.
441 lines
11 KiB
C++
441 lines
11 KiB
C++
/*
|
|
Derived from source code of TrueCrypt 7.1a, which is
|
|
Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
|
|
by the TrueCrypt License 3.0.
|
|
|
|
Modifications and additions to the original source code (contained in this file)
|
|
and all other portions of this file are Copyright (c) 2013-2025 AM Crypto
|
|
and are governed by the Apache License 2.0 the full text of which is
|
|
contained in the file License.txt included in VeraCrypt binary and source
|
|
code distribution packages.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <utime.h>
|
|
|
|
#ifdef TC_LINUX
|
|
#include <sys/mount.h>
|
|
#endif
|
|
|
|
#ifdef TC_BSD
|
|
#include <sys/disk.h>
|
|
#endif
|
|
|
|
#ifdef TC_OPENBSD
|
|
#include <sys/ioctl.h>
|
|
#include <sys/dkio.h>
|
|
#include <sys/disklabel.h>
|
|
#endif
|
|
|
|
#ifdef TC_SOLARIS
|
|
#include <stropts.h>
|
|
#include <sys/dkio.h>
|
|
#endif
|
|
|
|
#include <sys/file.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef TC_FREEBSD
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
|
|
#include "Platform/File.h"
|
|
#include "Platform/TextReader.h"
|
|
|
|
namespace VeraCrypt
|
|
{
|
|
#if 0
|
|
# define TC_TRACE_FILE_OPERATIONS
|
|
|
|
static void TraceFileOperation (int fileHandle, FilePath filePath, bool write, uint64 length, int64 position = -1)
|
|
{
|
|
string path = filePath;
|
|
if (path.empty() || path.find ("veracrypt_aux_mnt") != string::npos)
|
|
return;
|
|
|
|
stringstream s;
|
|
s << path << ": " << (write ? "W " : "R ") << (position == -1 ? lseek (fileHandle, 0, SEEK_CUR) : position) << " (" << length << ")";
|
|
SystemLog::WriteError (s.str());
|
|
}
|
|
#endif
|
|
|
|
void File::Close ()
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
if (!SharedHandle)
|
|
{
|
|
close (FileHandle);
|
|
FileIsOpen = false;
|
|
|
|
if ((mFileOpenFlags & File::PreserveTimestamps) && Path.IsFile())
|
|
{
|
|
struct utimbuf u;
|
|
u.actime = AccTime;
|
|
u.modtime = ModTime;
|
|
|
|
try
|
|
{
|
|
throw_sys_sub_if (utime (string (Path).c_str(), &u) == -1, wstring (Path));
|
|
}
|
|
catch (...) // Suppress errors to allow using read-only files
|
|
{
|
|
#ifdef DEBUG
|
|
throw;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void File::Delete ()
|
|
{
|
|
Close();
|
|
Path.Delete();
|
|
}
|
|
|
|
|
|
void File::Flush () const
|
|
{
|
|
if_debug (ValidateState());
|
|
throw_sys_sub_if (fsync (FileHandle) != 0, wstring (Path));
|
|
}
|
|
|
|
uint32 File::GetDeviceSectorSize () const
|
|
{
|
|
if (Path.IsDevice())
|
|
{
|
|
#ifdef TC_LINUX
|
|
int blockSize;
|
|
throw_sys_sub_if (ioctl (FileHandle, BLKSSZGET, &blockSize) == -1, wstring (Path));
|
|
return blockSize;
|
|
|
|
#elif defined (TC_MACOSX)
|
|
uint32 blockSize;
|
|
throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBLOCKSIZE, &blockSize) == -1, wstring (Path));
|
|
return blockSize;
|
|
|
|
#elif defined (TC_FREEBSD)
|
|
u_int sectorSize;
|
|
throw_sys_sub_if (ioctl (FileHandle, DIOCGSECTORSIZE, §orSize) == -1, wstring (Path));
|
|
return (uint32) sectorSize;
|
|
|
|
#elif defined (TC_OPENBSD)
|
|
struct disklabel dl;
|
|
throw_sys_sub_if (ioctl (FileHandle, DIOCGDINFO, &dl) == -1, wstring (Path));
|
|
|
|
if (dl.d_secsize == 0)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
return (uint32) dl.d_secsize;
|
|
|
|
#elif defined (TC_SOLARIS)
|
|
struct dk_minfo mediaInfo;
|
|
throw_sys_sub_if (ioctl (FileHandle, DKIOCGMEDIAINFO, &mediaInfo) == -1, wstring (Path));
|
|
return mediaInfo.dki_lbsize;
|
|
|
|
#else
|
|
# error GetDeviceSectorSize()
|
|
#endif
|
|
}
|
|
else
|
|
throw ParameterIncorrect (SRC_POS);
|
|
}
|
|
|
|
uint64 File::GetPartitionDeviceStartOffset () const
|
|
{
|
|
#ifdef TC_LINUX
|
|
|
|
// HDIO_GETGEO ioctl is limited by the size of long
|
|
TextReader tr ("/sys/block/" + string (Path.ToHostDriveOfPartition().ToBaseName()) + "/" + string (Path.ToBaseName()) + "/start");
|
|
|
|
string line;
|
|
tr.ReadLine (line);
|
|
return StringConverter::ToUInt64 (line) * GetDeviceSectorSize();
|
|
|
|
#elif defined (TC_MACOSX)
|
|
|
|
#ifndef DKIOCGETBASE
|
|
# define DKIOCGETBASE _IOR('d', 73, uint64)
|
|
#endif
|
|
uint64 offset;
|
|
throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBASE, &offset) == -1, wstring (Path));
|
|
return offset;
|
|
|
|
#elif defined (TC_FREEBSD)
|
|
// Get the kernel GEOM configuration
|
|
size_t sysctlDataLen, mibLen;
|
|
int mib[4];
|
|
mibLen = 4;
|
|
throw_sys_sub_if (sysctlnametomib ("kern.geom.conftxt", mib, &mibLen), wstring (Path));
|
|
throw_sys_sub_if (sysctl (mib, mibLen, NULL, &sysctlDataLen, NULL, 0), wstring (Path));
|
|
vector<char> conftxt(sysctlDataLen);
|
|
throw_sys_sub_if (sysctl (mib, mibLen, (void *)conftxt.data(), &sysctlDataLen, NULL, 0), wstring (Path));
|
|
|
|
// Find the slice/partition data
|
|
string conftxtStr (conftxt.begin(), conftxt.end());
|
|
size_t confLoc = conftxtStr.find (Path.ToBaseName());
|
|
throw_sys_sub_if (confLoc == string::npos, wstring (Path));
|
|
|
|
// Skip to the ninth column
|
|
for (int i = 0; i < 6;i++) {
|
|
confLoc = conftxtStr.find (" ", confLoc + 1);
|
|
throw_sys_sub_if (confLoc == string::npos, wstring (Path));
|
|
}
|
|
confLoc++;
|
|
size_t end = conftxtStr.find (" ", confLoc);
|
|
throw_sys_sub_if (end == string::npos, wstring (Path));
|
|
return StringConverter::ToUInt64 (conftxtStr.substr (confLoc, end - confLoc));
|
|
|
|
#elif defined (TC_SOLARIS)
|
|
|
|
struct extpart_info partInfo;
|
|
throw_sys_sub_if (ioctl (FileHandle, DKIOCEXTPARTINFO, &partInfo) == -1, wstring (Path));
|
|
return partInfo.p_start * GetDeviceSectorSize();
|
|
|
|
#else
|
|
throw NotImplemented (SRC_POS);
|
|
#endif
|
|
}
|
|
|
|
uint64 File::Length () const
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
// BSD does not support seeking to the end of a device
|
|
#ifdef TC_BSD
|
|
if (Path.IsBlockDevice() || Path.IsCharacterDevice())
|
|
{
|
|
# ifdef TC_MACOSX
|
|
uint32 blockSize;
|
|
uint64 blockCount;
|
|
throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBLOCKSIZE, &blockSize) == -1, wstring (Path));
|
|
throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBLOCKCOUNT, &blockCount) == -1, wstring (Path));
|
|
return blockCount * blockSize;
|
|
# elif TC_OPENBSD
|
|
struct disklabel dl;
|
|
struct stat statData;
|
|
throw_sys_sub_if (ioctl (FileHandle, DIOCGDINFO, &dl) == -1, wstring (Path));
|
|
throw_sys_sub_if (fstat (FileHandle, &statData) == -1, wstring (Path));
|
|
|
|
if (dl.d_secsize == 0)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
uint64 sectors;
|
|
int partition = DISKPART (statData.st_rdev);
|
|
if (partition == RAW_PART)
|
|
{
|
|
sectors = DL_GETDSIZE (&dl);
|
|
}
|
|
else
|
|
{
|
|
if (partition < 0 || partition >= dl.d_npartitions)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
sectors = DL_GETPSIZE (&dl.d_partitions[partition]);
|
|
}
|
|
|
|
if (sectors > ((uint64) -1) / dl.d_secsize)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
return sectors * dl.d_secsize;
|
|
# else
|
|
uint64 mediaSize;
|
|
throw_sys_sub_if (ioctl (FileHandle, DIOCGMEDIASIZE, &mediaSize) == -1, wstring (Path));
|
|
return mediaSize;
|
|
# endif
|
|
}
|
|
#endif
|
|
#ifdef TC_LINUX
|
|
// On Linux, try to use BLKGETSIZE64 for devices
|
|
if (Path.IsDevice())
|
|
{
|
|
uint64 mediaSize;
|
|
if (ioctl (FileHandle, BLKGETSIZE64, &mediaSize) != -1)
|
|
{
|
|
return mediaSize;
|
|
}
|
|
}
|
|
#endif
|
|
off_t current = lseek (FileHandle, 0, SEEK_CUR);
|
|
throw_sys_sub_if (current == -1, wstring (Path));
|
|
SeekEnd (0);
|
|
uint64 length = lseek (FileHandle, 0, SEEK_CUR);
|
|
SeekAt (current);
|
|
return length;
|
|
}
|
|
|
|
void File::Open (const FilePath &path, FileOpenMode mode, FileShareMode shareMode, FileOpenFlags flags)
|
|
{
|
|
#ifdef TC_LINUX
|
|
int sysFlags = O_LARGEFILE;
|
|
#else
|
|
int sysFlags = 0;
|
|
#endif
|
|
|
|
switch (mode)
|
|
{
|
|
case CreateReadWrite:
|
|
sysFlags |= O_CREAT | O_TRUNC | O_RDWR;
|
|
break;
|
|
|
|
case CreateWrite:
|
|
sysFlags |= O_CREAT | O_TRUNC | O_WRONLY;
|
|
break;
|
|
|
|
case OpenRead:
|
|
sysFlags |= O_RDONLY;
|
|
break;
|
|
|
|
case OpenWrite:
|
|
sysFlags |= O_WRONLY;
|
|
break;
|
|
|
|
case OpenReadWrite:
|
|
sysFlags |= O_RDWR;
|
|
break;
|
|
|
|
default:
|
|
throw ParameterIncorrect (SRC_POS);
|
|
}
|
|
|
|
if ((flags & File::PreserveTimestamps) && path.IsFile())
|
|
{
|
|
struct stat statData;
|
|
throw_sys_sub_if (stat (string (path).c_str(), &statData) == -1, wstring (path));
|
|
AccTime = statData.st_atime;
|
|
ModTime = statData.st_mtime;
|
|
}
|
|
|
|
FileHandle = open (string (path).c_str(), sysFlags, S_IRUSR | S_IWUSR);
|
|
throw_sys_sub_if (FileHandle == -1, wstring (path));
|
|
|
|
#if 0 // File locking is disabled to avoid remote filesystem locking issues
|
|
try
|
|
{
|
|
struct flock fl;
|
|
memset (&fl, 0, sizeof (fl));
|
|
fl.l_whence = SEEK_SET;
|
|
fl.l_start = 0;
|
|
fl.l_len = 0;
|
|
|
|
switch (shareMode)
|
|
{
|
|
case ShareNone:
|
|
fl.l_type = F_WRLCK;
|
|
if (fcntl (FileHandle, F_SETLK, &fl) == -1)
|
|
throw_sys_sub_if (errno == EAGAIN || errno == EACCES, wstring (path));
|
|
break;
|
|
|
|
case ShareRead:
|
|
fl.l_type = F_RDLCK;
|
|
if (fcntl (FileHandle, F_SETLK, &fl) == -1)
|
|
throw_sys_sub_if (errno == EAGAIN || errno == EACCES, wstring (path));
|
|
break;
|
|
|
|
case ShareReadWrite:
|
|
fl.l_type = (mode == OpenRead ? F_RDLCK : F_WRLCK);
|
|
if (fcntl (FileHandle, F_GETLK, &fl) != -1 && fl.l_type != F_UNLCK)
|
|
{
|
|
errno = EAGAIN;
|
|
throw SystemException (SRC_POS, wstring (path));
|
|
}
|
|
break;
|
|
|
|
case ShareReadWriteIgnoreLock:
|
|
break;
|
|
|
|
default:
|
|
throw ParameterIncorrect (SRC_POS);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
close (FileHandle);
|
|
throw;
|
|
}
|
|
#endif // 0
|
|
|
|
Path = path;
|
|
mFileOpenFlags = flags;
|
|
FileIsOpen = true;
|
|
}
|
|
|
|
uint64 File::Read (const BufferPtr &buffer) const
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
#ifdef TC_TRACE_FILE_OPERATIONS
|
|
TraceFileOperation (FileHandle, Path, false, buffer.Size());
|
|
#endif
|
|
ssize_t bytesRead = read (FileHandle, buffer, buffer.Size());
|
|
throw_sys_sub_if (bytesRead == -1, wstring (Path));
|
|
|
|
return bytesRead;
|
|
}
|
|
|
|
uint64 File::ReadAt (const BufferPtr &buffer, uint64 position) const
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
#ifdef TC_TRACE_FILE_OPERATIONS
|
|
TraceFileOperation (FileHandle, Path, false, buffer.Size(), position);
|
|
#endif
|
|
ssize_t bytesRead = pread (FileHandle, buffer, buffer.Size(), position);
|
|
throw_sys_sub_if (bytesRead == -1, wstring (Path));
|
|
|
|
return bytesRead;
|
|
}
|
|
|
|
void File::SeekAt (uint64 position) const
|
|
{
|
|
if_debug (ValidateState());
|
|
throw_sys_sub_if (lseek (FileHandle, position, SEEK_SET) == -1, wstring (Path));
|
|
}
|
|
|
|
void File::SeekEnd (int offset) const
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
// BSD does not support seeking to the end of a device
|
|
#ifdef TC_BSD
|
|
if (Path.IsBlockDevice() || Path.IsCharacterDevice())
|
|
{
|
|
SeekAt (Length() + offset);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
throw_sys_sub_if (lseek (FileHandle, offset, SEEK_END) == -1, wstring (Path));
|
|
}
|
|
|
|
void File::SetLength (uint64 length) const
|
|
{
|
|
if_debug (ValidateState());
|
|
throw_sys_sub_if (ftruncate (FileHandle, length) == -1, wstring (Path));
|
|
}
|
|
|
|
void File::Write (const ConstBufferPtr &buffer) const
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
#ifdef TC_TRACE_FILE_OPERATIONS
|
|
TraceFileOperation (FileHandle, Path, true, buffer.Size());
|
|
#endif
|
|
throw_sys_sub_if (write (FileHandle, buffer, buffer.Size()) != (ssize_t) buffer.Size(), wstring (Path));
|
|
}
|
|
|
|
void File::WriteAt (const ConstBufferPtr &buffer, uint64 position) const
|
|
{
|
|
if_debug (ValidateState());
|
|
|
|
#ifdef TC_TRACE_FILE_OPERATIONS
|
|
TraceFileOperation (FileHandle, Path, true, buffer.Size(), position);
|
|
#endif
|
|
throw_sys_sub_if (pwrite (FileHandle, buffer, buffer.Size(), position) != (ssize_t) buffer.Size(), wstring (Path));
|
|
}
|
|
}
|