mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-10-05 16:46:35 -05:00
fix(macos): ensure FUSE-T service exits during dismount (#1866)
Add an authenticated shutdown endpoint to the auxiliary FUSE filesystem and wait for the matching service process to terminate before removing the mount point.
This commit is contained in:
1 parent
b111be60d2
commit
d7bc65bed0
3 files changed
+224
No files matched your search
@@ -317,12 +317,25 @@ namespace VeraCrypt
|
|||||||
mountedVolume = ml.front();
|
mountedVolume = ml.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef VC_MACOSX_FUSET
|
||||||
|
pid_t fuseServiceProcessId = FuseService::RequestDismount (mountedVolume->AuxMountPoint,
|
||||||
|
mountedVolume->SerialInstanceNumber, mountedVolume->SlotNumber);
|
||||||
|
#endif
|
||||||
|
|
||||||
list <string> args;
|
list <string> args;
|
||||||
args.push_back ("--");
|
args.push_back ("--");
|
||||||
args.push_back (mountedVolume->AuxMountPoint);
|
args.push_back (mountedVolume->AuxMountPoint);
|
||||||
|
|
||||||
for (int t = 0; true; t++)
|
for (int t = 0; true; t++)
|
||||||
{
|
{
|
||||||
|
#ifdef VC_MACOSX_FUSET
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (GetMountedFilesystems (DevicePath(), mountedVolume->AuxMountPoint).empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (...) { }
|
||||||
|
#endif
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process::Execute ("/sbin/umount", args);
|
Process::Execute ("/sbin/umount", args);
|
||||||
@@ -336,6 +349,10 @@ namespace VeraCrypt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef VC_MACOSX_FUSET
|
||||||
|
FuseService::WaitForDismount (fuseServiceProcessId, mountedVolume->AuxMountPoint, mountedVolume->SlotNumber);
|
||||||
|
#endif
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mountedVolume->AuxMountPoint.Delete();
|
mountedVolume->AuxMountPoint.Delete();
|
||||||
|
|||||||
@@ -34,8 +34,10 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
|
#include <atomic>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <sstream>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -46,6 +48,13 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "FuseService.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/FileStream.h"
|
||||||
#include "Platform/MemoryStream.h"
|
#include "Platform/MemoryStream.h"
|
||||||
#include "Platform/Serializable.h"
|
#include "Platform/Serializable.h"
|
||||||
@@ -62,6 +71,16 @@ namespace VeraCrypt
|
|||||||
static const ino_t VC_FUSE_INODE_VOLUME = 2;
|
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_CONTROL = 3;
|
||||||
static const ino_t VC_FUSE_INODE_AUX_DEVICE_INFO = 4;
|
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_BLOCK_SIZE = 4096;
|
||||||
static const uint64 VC_FUSE_METADATA_SIZE = 64 * 1024;
|
static const uint64 VC_FUSE_METADATA_SIZE = 64 * 1024;
|
||||||
static const uint64 VC_FUSE_STAT_BLOCK_SIZE = 512;
|
static const uint64 VC_FUSE_STAT_BLOCK_SIZE = 512;
|
||||||
@@ -85,6 +104,51 @@ namespace VeraCrypt
|
|||||||
return FuseService::GetVolumeInfo();
|
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)
|
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;
|
struct stat st;
|
||||||
@@ -234,6 +298,16 @@ namespace VeraCrypt
|
|||||||
statData->st_ino = VC_FUSE_INODE_CONTROL;
|
statData->st_ino = VC_FUSE_INODE_CONTROL;
|
||||||
fuse_service_set_stat_blocks (statData);
|
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
|
else
|
||||||
{
|
{
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@@ -330,6 +404,14 @@ namespace VeraCrypt
|
|||||||
fi->direct_io = 1;
|
fi->direct_io = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(TC_MACOSX) && defined(VC_MACOSX_FUSET)
|
||||||
|
if (strcmp (path, FuseService::GetShutdownPath()) == 0)
|
||||||
|
{
|
||||||
|
fi->direct_io = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@@ -412,6 +494,24 @@ namespace VeraCrypt
|
|||||||
outBuf.CopyFrom (infoBuf->GetRange (offset, size));
|
outBuf.CopyFrom (infoBuf->GetRange (offset, size));
|
||||||
return 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 (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@@ -461,6 +561,10 @@ namespace VeraCrypt
|
|||||||
return 0;
|
return 0;
|
||||||
if (fuse_service_fill_dir_entry (buf, filler, FuseService::GetAuxDeviceInfoPath() + 1, S_IFREG | 0600, VC_FUSE_INODE_AUX_DEVICE_INFO, 0) != 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;
|
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 (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@@ -506,6 +610,42 @@ namespace VeraCrypt
|
|||||||
FuseService::ReceiveAuxDeviceInfo (ConstBufferPtr ((const uint8 *) buf, size));
|
FuseService::ReceiveAuxDeviceInfo (ConstBufferPtr ((const uint8 *) buf, size));
|
||||||
return 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
|
#ifdef TC_FREEBSD
|
||||||
// FreeBSD apparently retries failed write operations forever, which may lead to a system crash.
|
// FreeBSD apparently retries failed write operations forever, which may lead to a system crash.
|
||||||
@@ -742,6 +882,64 @@ namespace VeraCrypt
|
|||||||
fuseServiceControl.Close();
|
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)
|
void FuseService::WriteVolumeSectors (const ConstBufferPtr &buffer, uint64 byteOffset)
|
||||||
{
|
{
|
||||||
if (!MountedVolume)
|
if (!MountedVolume)
|
||||||
|
|||||||
@@ -48,9 +48,14 @@ namespace VeraCrypt
|
|||||||
static const char *GetAuxDeviceInfoPath () { return "/aux-device-info"; }
|
static const char *GetAuxDeviceInfoPath () { return "/aux-device-info"; }
|
||||||
static const char *GetControlPath () { return "/control"; }
|
static const char *GetControlPath () { return "/control"; }
|
||||||
static const char *GetVolumeImagePath ();
|
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 string GetDeviceType () { return "veracrypt"; }
|
||||||
static gid_t GetGroupId () { return GroupId; }
|
static gid_t GetGroupId () { return GroupId; }
|
||||||
static uid_t GetUserId () { return UserId; }
|
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> GetAuxDeviceInfo ();
|
||||||
static shared_ptr <Buffer> GetVolumeInfo ();
|
static shared_ptr <Buffer> GetVolumeInfo ();
|
||||||
static uint64 GetVolumeSize ();
|
static uint64 GetVolumeSize ();
|
||||||
@@ -59,6 +64,10 @@ namespace VeraCrypt
|
|||||||
static void ReadVolumeSectors (const BufferPtr &buffer, uint64 byteOffset);
|
static void ReadVolumeSectors (const BufferPtr &buffer, uint64 byteOffset);
|
||||||
static void ReceiveAuxDeviceInfo (const ConstBufferPtr &buffer);
|
static void ReceiveAuxDeviceInfo (const ConstBufferPtr &buffer);
|
||||||
static void SendAuxDeviceInfo (const DirectoryPath &fuseMountPoint, const DevicePath &virtualDevice, const DevicePath &loopDevice = DevicePath());
|
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);
|
static void WriteVolumeSectors (const ConstBufferPtr &buffer, uint64 byteOffset);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in new issue
Block a user