Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/Core/Unix/MacOSX/CoreMacOSX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,25 @@ namespace VeraCrypt
mountedVolume = ml.front();
}

#ifdef VC_MACOSX_FUSET
pid_t fuseServiceProcessId = FuseService::RequestDismount (mountedVolume->AuxMountPoint,
mountedVolume->SerialInstanceNumber, mountedVolume->SlotNumber);
#endif

list <string> args;
args.push_back ("--");
args.push_back (mountedVolume->AuxMountPoint);

for (int t = 0; true; t++)
{
#ifdef VC_MACOSX_FUSET
try
{
if (GetMountedFilesystems (DevicePath(), mountedVolume->AuxMountPoint).empty())
break;
}
catch (...) { }
#endif
try
{
Process::Execute ("/sbin/umount", args);
Expand All @@ -336,6 +349,10 @@ namespace VeraCrypt
}
}

#ifdef VC_MACOSX_FUSET
FuseService::WaitForDismount (fuseServiceProcessId, mountedVolume->AuxMountPoint, mountedVolume->SlotNumber);
#endif

try
{
mountedVolume->AuxMountPoint.Delete();
Expand Down
198 changes: 198 additions & 0 deletions src/Driver/Fuse/FuseService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
#include <errno.h>
#include <fcntl.h>
#include <fuse.h>
#include <atomic>
#include <iostream>
#include <signal.h>
#include <sstream>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
Expand All @@ -46,6 +48,13 @@
#include <sys/wait.h>

#include "FuseService.h"
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
#include <fuse_lowlevel.h>
#undef fuse_unmount
#ifdef ERR_SUCCESS
#undef ERR_SUCCESS
#endif
#endif
#include "Platform/FileStream.h"
#include "Platform/MemoryStream.h"
#include "Platform/Serializable.h"
Expand All @@ -62,6 +71,16 @@ namespace VeraCrypt
static const ino_t VC_FUSE_INODE_VOLUME = 2;
static const ino_t VC_FUSE_INODE_CONTROL = 3;
static const ino_t VC_FUSE_INODE_AUX_DEVICE_INFO = 4;
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
static const ino_t VC_FUSE_INODE_SHUTDOWN = 5;
static atomic <bool> FuseServiceShutdownRequested (false);

struct FuseServiceShutdownContext
{
explicit FuseServiceShutdownContext (struct fuse *fuseHandle) : FuseHandle (fuseHandle) { }
struct fuse *FuseHandle;
};
#endif
static const uint64 VC_FUSE_BLOCK_SIZE = 4096;
static const uint64 VC_FUSE_METADATA_SIZE = 64 * 1024;
static const uint64 VC_FUSE_STAT_BLOCK_SIZE = 512;
Expand All @@ -85,6 +104,51 @@ namespace VeraCrypt
return FuseService::GetVolumeInfo();
}

#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
static string fuse_service_get_shutdown_identity ()
{
stringstream identity;
identity << getpid() << " " << FuseService::GetSerialInstanceNumber() << " " << FuseService::GetSlotNumber() << "\n";
return identity.str();
}

static bool fuse_service_parse_shutdown_identity (const string &identity, pid_t &processId, uint64 &serialInstanceNumber, VolumeSlotNumber &slotNumber)
{
long long parsedProcessId;
uint64 parsedSerialInstanceNumber;
VolumeSlotNumber parsedSlotNumber;
stringstream parser (identity);

if (!(parser >> parsedProcessId >> parsedSerialInstanceNumber >> parsedSlotNumber))
return false;

parser >> ws;
if (!parser.eof() || parsedProcessId <= 1 || static_cast <pid_t> (parsedProcessId) != parsedProcessId)
return false;

processId = static_cast <pid_t> (parsedProcessId);
serialInstanceNumber = parsedSerialInstanceNumber;
slotNumber = parsedSlotNumber;
return true;
}

static TC_THREAD_PROC fuse_service_shutdown (void *contextArg)
{
unique_ptr <FuseServiceShutdownContext> context (static_cast <FuseServiceShutdownContext *> (contextArg));

// Let the write reply reach the caller before closing FUSE-T's channel.
Thread::Sleep (100);
fuse_exit (context->FuseHandle);

struct fuse_session *session = fuse_get_session (context->FuseHandle);
struct fuse_chan *channel = session ? fuse_session_next_chan (session, NULL) : NULL;
if (channel)
fuse_unmount (NULL, channel);

return 0;
}
#endif

static int fuse_service_fill_dir_entry (void *buf, fuse_fill_dir_t filler, const char *name, mode_t mode, ino_t ino, off_t nextOff)
{
struct stat st;
Expand Down Expand Up @@ -234,6 +298,16 @@ namespace VeraCrypt
statData->st_ino = VC_FUSE_INODE_CONTROL;
fuse_service_set_stat_blocks (statData);
}
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
else if (strcmp (path, FuseService::GetShutdownPath()) == 0)
{
statData->st_mode = S_IFREG | 0600;
statData->st_nlink = 1;
statData->st_size = fuse_service_get_shutdown_identity().size();
statData->st_ino = VC_FUSE_INODE_SHUTDOWN;
fuse_service_set_stat_blocks (statData);
}
#endif
else
{
return -ENOENT;
Expand Down Expand Up @@ -330,6 +404,14 @@ namespace VeraCrypt
fi->direct_io = 1;
return 0;
}

#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
if (strcmp (path, FuseService::GetShutdownPath()) == 0)
{
fi->direct_io = 1;
return 0;
}
#endif
}
catch (...)
{
Expand Down Expand Up @@ -412,6 +494,24 @@ namespace VeraCrypt
outBuf.CopyFrom (infoBuf->GetRange (offset, size));
return size;
}

#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
if (strcmp (path, FuseService::GetShutdownPath()) == 0)
{
string identity = fuse_service_get_shutdown_identity();
if (offset < 0)
return -EINVAL;

if (offset >= (off_t) identity.size())
return 0;

if (offset + size > identity.size())
size = identity.size() - offset;

memcpy (buf, identity.data() + offset, size);
return size;
}
#endif
}
catch (...)
{
Expand Down Expand Up @@ -461,6 +561,10 @@ namespace VeraCrypt
return 0;
if (fuse_service_fill_dir_entry (buf, filler, FuseService::GetAuxDeviceInfoPath() + 1, S_IFREG | 0600, VC_FUSE_INODE_AUX_DEVICE_INFO, 0) != 0)
return 0;
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
if (fuse_service_fill_dir_entry (buf, filler, FuseService::GetShutdownPath() + 1, S_IFREG | 0600, VC_FUSE_INODE_SHUTDOWN, 0) != 0)
return 0;
#endif
}
catch (...)
{
Expand Down Expand Up @@ -506,6 +610,42 @@ namespace VeraCrypt
FuseService::ReceiveAuxDeviceInfo (ConstBufferPtr ((const uint8 *) buf, size));
return size;
}

#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
if (strcmp (path, FuseService::GetShutdownPath()) == 0)
{
pid_t processId;
uint64 serialInstanceNumber;
VolumeSlotNumber slotNumber;
struct fuse_context *context = fuse_get_context();

if (offset != 0 || !context || !context->fuse
|| !fuse_service_parse_shutdown_identity (string (buf, size), processId, serialInstanceNumber, slotNumber)
|| processId != getpid()
|| serialInstanceNumber != FuseService::GetSerialInstanceNumber()
|| slotNumber != FuseService::GetSlotNumber())
return -EINVAL;

bool expected = false;
if (FuseServiceShutdownRequested.compare_exchange_strong (expected, true))
{
try
{
unique_ptr <FuseServiceShutdownContext> shutdownContext (new FuseServiceShutdownContext (context->fuse));
Thread shutdownThread;
shutdownThread.Start (fuse_service_shutdown, shutdownContext.get());
shutdownContext.release();
shutdownThread.Detach();
}
catch (...)
{
FuseServiceShutdownRequested = false;
throw;
}
}
return size;
}
#endif
}
#ifdef TC_FREEBSD
// FreeBSD apparently retries failed write operations forever, which may lead to a system crash.
Expand Down Expand Up @@ -742,6 +882,64 @@ namespace VeraCrypt
fuseServiceControl.Close();
}

#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
pid_t FuseService::RequestDismount (const DirectoryPath &fuseMountPoint, uint64 serialInstanceNumber, VolumeSlotNumber slotNumber)
{
shared_ptr <File> shutdownFile (new File);
shutdownFile->Open (string (fuseMountPoint) + GetShutdownPath());

FileStream shutdownReader (shutdownFile);
string identity = shutdownReader.ReadToEnd();
shutdownFile->Close();
if (identity.empty() || identity.size() > 256)
throw ParameterIncorrect (SRC_POS);

pid_t processId;
uint64 serviceSerialInstanceNumber;
VolumeSlotNumber serviceSlotNumber;
if (!fuse_service_parse_shutdown_identity (identity, processId, serviceSerialInstanceNumber, serviceSlotNumber)
|| serviceSerialInstanceNumber != serialInstanceNumber || serviceSlotNumber != slotNumber)
{
stringstream logMessage;
logMessage << "Refusing to shut down mismatched VeraCrypt FUSE service: slot=" << slotNumber
<< ", auxiliary mount=" << string (fuseMountPoint);
SystemLog::WriteError (logMessage.str());
throw ParameterIncorrect (SRC_POS);
}

shutdownFile->Open (string (fuseMountPoint) + GetShutdownPath(), File::OpenWrite);
shutdownFile->Write (ConstBufferPtr (reinterpret_cast <const uint8 *> (identity.data()), identity.size()));
shutdownFile->Close();
return processId;
}

void FuseService::WaitForDismount (pid_t processId, const DirectoryPath &fuseMountPoint, VolumeSlotNumber slotNumber, int timeOut)
{
for (int timeTaken = 0; ; timeTaken += 100)
{
if (kill (processId, 0) == -1)
{
if (errno == ESRCH)
return;

if (errno != EPERM)
throw SystemException (SRC_POS);
}

if (timeTaken >= timeOut)
{
stringstream logMessage;
logMessage << "VeraCrypt FUSE service did not terminate after shutdown request: pid=" << processId
<< ", slot=" << slotNumber << ", auxiliary mount=" << string (fuseMountPoint);
SystemLog::WriteError (logMessage.str());
throw TimeOut (SRC_POS);
}

Thread::Sleep (100);
}
}
#endif

void FuseService::WriteVolumeSectors (const ConstBufferPtr &buffer, uint64 byteOffset)
{
if (!MountedVolume)
Expand Down
9 changes: 9 additions & 0 deletions src/Driver/Fuse/FuseService.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ namespace VeraCrypt
static const char *GetAuxDeviceInfoPath () { return "/aux-device-info"; }
static const char *GetControlPath () { return "/control"; }
static const char *GetVolumeImagePath ();
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
static const char *GetShutdownPath () { return "/shutdown"; }
#endif
static string GetDeviceType () { return "veracrypt"; }
static gid_t GetGroupId () { return GroupId; }
static uid_t GetUserId () { return UserId; }
static uint64 GetSerialInstanceNumber () { return OpenVolumeInfo.SerialInstanceNumber; }
static VolumeSlotNumber GetSlotNumber () { return SlotNumber; }
static shared_ptr <Buffer> GetAuxDeviceInfo ();
static shared_ptr <Buffer> GetVolumeInfo ();
static uint64 GetVolumeSize ();
Expand All @@ -59,6 +64,10 @@ namespace VeraCrypt
static void ReadVolumeSectors (const BufferPtr &buffer, uint64 byteOffset);
static void ReceiveAuxDeviceInfo (const ConstBufferPtr &buffer);
static void SendAuxDeviceInfo (const DirectoryPath &fuseMountPoint, const DevicePath &virtualDevice, const DevicePath &loopDevice = DevicePath());
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
static pid_t RequestDismount (const DirectoryPath &fuseMountPoint, uint64 serialInstanceNumber, VolumeSlotNumber slotNumber);
static void WaitForDismount (pid_t processId, const DirectoryPath &fuseMountPoint, VolumeSlotNumber slotNumber, int timeOut = 10000);
#endif
static void WriteVolumeSectors (const ConstBufferPtr &buffer, uint64 byteOffset);

protected:
Expand Down