"Fossies" - the Fresh Open Source Software Archive

Member "src/Driver/Fuse/FuseService.cpp" (10 Oct 2018, 13806 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "FuseService.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #define FUSE_USE_VERSION  25
   14 #include <errno.h>
   15 #include <fcntl.h>
   16 #include <fuse.h>
   17 #include <iostream>
   18 #include <signal.h>
   19 #include <string.h>
   20 #include <stdio.h>
   21 #include <unistd.h>
   22 #include <time.h>
   23 #include <sys/mman.h>
   24 #include <sys/time.h>
   25 #include <sys/wait.h>
   26 
   27 #include "FuseService.h"
   28 #include "Platform/FileStream.h"
   29 #include "Platform/MemoryStream.h"
   30 #include "Platform/Serializable.h"
   31 #include "Platform/SystemLog.h"
   32 #include "Platform/Unix/Pipe.h"
   33 #include "Platform/Unix/Poller.h"
   34 #include "Volume/EncryptionThreadPool.h"
   35 #include "Core/Core.h"
   36 
   37 namespace VeraCrypt
   38 {
   39     static int fuse_service_access (const char *path, int mask)
   40     {
   41         try
   42         {
   43             if (!FuseService::CheckAccessRights())
   44                 return -EACCES;
   45         }
   46         catch (...)
   47         {
   48             return FuseService::ExceptionToErrorCode();
   49         }
   50 
   51         return 0;
   52     }
   53 
   54     static void *fuse_service_init ()
   55     {
   56         try
   57         {
   58             // Termination signals are handled by a separate process to allow clean dismount on shutdown
   59             struct sigaction action;
   60             Memory::Zero (&action, sizeof (action));
   61             action.sa_handler = SIG_IGN;
   62 
   63             sigaction (SIGINT, &action, nullptr);
   64             sigaction (SIGQUIT, &action, nullptr);
   65             sigaction (SIGTERM, &action, nullptr);
   66 
   67             if (!EncryptionThreadPool::IsRunning())
   68                 EncryptionThreadPool::Start();
   69         }
   70         catch (exception &e)
   71         {
   72             SystemLog::WriteException (e);
   73         }
   74         catch (...)
   75         {
   76             SystemLog::WriteException (UnknownException (SRC_POS));
   77         }
   78 
   79         return nullptr;
   80     }
   81 
   82     static void fuse_service_destroy (void *userdata)
   83     {
   84         try
   85         {
   86             FuseService::Dismount();
   87         }
   88         catch (exception &e)
   89         {
   90             SystemLog::WriteException (e);
   91         }
   92         catch (...)
   93         {
   94             SystemLog::WriteException (UnknownException (SRC_POS));
   95         }
   96     }
   97 
   98     static int fuse_service_getattr (const char *path, struct stat *statData)
   99     {
  100         try
  101         {
  102             Memory::Zero (statData, sizeof(*statData));
  103 
  104             statData->st_uid = FuseService::GetUserId();
  105             statData->st_gid = FuseService::GetGroupId();
  106             statData->st_atime = time (NULL);
  107             statData->st_ctime = time (NULL);
  108             statData->st_mtime = time (NULL);
  109 
  110             if (strcmp (path, "/") == 0)
  111             {
  112                 statData->st_mode = S_IFDIR | 0500;
  113                 statData->st_nlink = 2;
  114             }
  115             else
  116             {
  117                 if (!FuseService::CheckAccessRights())
  118                     return -EACCES;
  119 
  120                 if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
  121                 {
  122                     statData->st_mode = S_IFREG | 0600;
  123                     statData->st_nlink = 1;
  124                     statData->st_size = FuseService::GetVolumeSize();
  125                 }
  126                 else if (strcmp (path, FuseService::GetControlPath()) == 0)
  127                 {
  128                     statData->st_mode = S_IFREG | 0600;
  129                     statData->st_nlink = 1;
  130                     statData->st_size = FuseService::GetVolumeInfo()->Size();
  131                 }
  132                 else
  133                 {
  134                     return -ENOENT;
  135                 }
  136             }
  137         }
  138         catch (...)
  139         {
  140             return FuseService::ExceptionToErrorCode();
  141         }
  142 
  143         return 0;
  144     }
  145 
  146     static int fuse_service_opendir (const char *path, struct fuse_file_info *fi)
  147     {
  148         try
  149         {
  150             if (!FuseService::CheckAccessRights())
  151                 return -EACCES;
  152 
  153             if (strcmp (path, "/") != 0)
  154                 return -ENOENT;
  155         }
  156         catch (...)
  157         {
  158             return FuseService::ExceptionToErrorCode();
  159         }
  160 
  161         return 0;
  162     }
  163 
  164     static int fuse_service_open (const char *path, struct fuse_file_info *fi)
  165     {
  166         try
  167         {
  168             if (!FuseService::CheckAccessRights())
  169                 return -EACCES;
  170 
  171             if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
  172                 return 0;
  173 
  174             if (strcmp (path, FuseService::GetControlPath()) == 0)
  175             {
  176                 fi->direct_io = 1;
  177                 return 0;
  178             }
  179         }
  180         catch (...)
  181         {
  182             return FuseService::ExceptionToErrorCode();
  183         }
  184         return -ENOENT;
  185     }
  186 
  187     static int fuse_service_read (const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
  188     {
  189         try
  190         {
  191             if (!FuseService::CheckAccessRights())
  192                 return -EACCES;
  193 
  194             if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
  195             {
  196                 try
  197                 {
  198                     // Test for read beyond the end of the volume
  199                     if ((uint64) offset + size > FuseService::GetVolumeSize())
  200                         size = FuseService::GetVolumeSize() - offset;
  201 
  202                     size_t sectorSize = FuseService::GetVolumeSectorSize();
  203                     if (size % sectorSize != 0 || offset % sectorSize != 0)
  204                     {
  205                         // Support for non-sector-aligned read operations is required by some loop device tools
  206                         // which may analyze the volume image before attaching it as a device
  207 
  208                         uint64 alignedOffset = offset - (offset % sectorSize);
  209                         uint64 alignedSize = size + (offset % sectorSize);
  210 
  211                         if (alignedSize % sectorSize != 0)
  212                             alignedSize += sectorSize - (alignedSize % sectorSize);
  213 
  214                         SecureBuffer alignedBuffer (alignedSize);
  215 
  216                         FuseService::ReadVolumeSectors (alignedBuffer, alignedOffset);
  217                         BufferPtr ((byte *) buf, size).CopyFrom (alignedBuffer.GetRange (offset % sectorSize, size));
  218                     }
  219                     else
  220                     {
  221                         FuseService::ReadVolumeSectors (BufferPtr ((byte *) buf, size), offset);
  222                     }
  223                 }
  224                 catch (MissingVolumeData)
  225                 {
  226                     return 0;
  227                 }
  228 
  229                 return size;
  230             }
  231 
  232             if (strcmp (path, FuseService::GetControlPath()) == 0)
  233             {
  234                 shared_ptr <Buffer> infoBuf = FuseService::GetVolumeInfo();
  235                 BufferPtr outBuf ((byte *)buf, size);
  236 
  237                 if (offset >= (off_t) infoBuf->Size())
  238                     return 0;
  239 
  240                 if (offset + size > infoBuf->Size())
  241                     size = infoBuf->Size () - offset;
  242 
  243                 outBuf.CopyFrom (infoBuf->GetRange (offset, size));
  244                 return size;
  245             }
  246         }
  247         catch (...)
  248         {
  249             return FuseService::ExceptionToErrorCode();
  250         }
  251 
  252         return -ENOENT;
  253     }
  254 
  255     static int fuse_service_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
  256     {
  257         try
  258         {
  259             if (!FuseService::CheckAccessRights())
  260                 return -EACCES;
  261 
  262             if (strcmp (path, "/") != 0)
  263                 return -ENOENT;
  264 
  265             filler (buf, ".", NULL, 0);
  266             filler (buf, "..", NULL, 0);
  267             filler (buf, FuseService::GetVolumeImagePath() + 1, NULL, 0);
  268             filler (buf, FuseService::GetControlPath() + 1, NULL, 0);
  269         }
  270         catch (...)
  271         {
  272             return FuseService::ExceptionToErrorCode();
  273         }
  274 
  275         return 0;
  276     }
  277 
  278     static int fuse_service_write (const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
  279     {
  280         try
  281         {
  282             if (!FuseService::CheckAccessRights())
  283                 return -EACCES;
  284 
  285             if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
  286             {
  287                 FuseService::WriteVolumeSectors (BufferPtr ((byte *) buf, size), offset);
  288                 return size;
  289             }
  290 
  291             if (strcmp (path, FuseService::GetControlPath()) == 0)
  292             {
  293                 if (FuseService::AuxDeviceInfoReceived())
  294                     return -EACCES;
  295 
  296                 FuseService::ReceiveAuxDeviceInfo (ConstBufferPtr ((const byte *)buf, size));
  297                 return size;
  298             }
  299         }
  300 #ifdef TC_FREEBSD
  301         // FreeBSD apparently retries failed write operations forever, which may lead to a system crash.
  302         catch (VolumeReadOnly&)
  303         {
  304             return size;
  305         }
  306         catch (VolumeProtected&)
  307         {
  308             return size;
  309         }
  310 #endif
  311         catch (...)
  312         {
  313             return FuseService::ExceptionToErrorCode();
  314         }
  315 
  316         return -ENOENT;
  317     }
  318 
  319     bool FuseService::CheckAccessRights ()
  320     {
  321         return fuse_get_context()->uid == 0 || fuse_get_context()->uid == UserId;
  322     }
  323 
  324     void FuseService::CloseMountedVolume ()
  325     {
  326         if (MountedVolume)
  327         {
  328             // This process will exit before the use count of MountedVolume reaches zero
  329             if (MountedVolume->GetFile().use_count() > 1)
  330                 MountedVolume->GetFile()->Close();
  331 
  332             if (MountedVolume.use_count() > 1)
  333                 delete MountedVolume.get();
  334 
  335             MountedVolume.reset();
  336         }
  337     }
  338 
  339     void FuseService::Dismount ()
  340     {
  341         CloseMountedVolume();
  342 
  343         if (EncryptionThreadPool::IsRunning())
  344             EncryptionThreadPool::Stop();
  345     }
  346 
  347     int FuseService::ExceptionToErrorCode ()
  348     {
  349         try
  350         {
  351             throw;
  352         }
  353         catch (std::bad_alloc)
  354         {
  355             return -ENOMEM;
  356         }
  357         catch (ParameterIncorrect &e)
  358         {
  359             SystemLog::WriteException (e);
  360             return -EINVAL;
  361         }
  362         catch (VolumeProtected&)
  363         {
  364             return -EPERM;
  365         }
  366         catch (VolumeReadOnly&)
  367         {
  368             return -EPERM;
  369         }
  370         catch (SystemException &e)
  371         {
  372             SystemLog::WriteException (e);
  373             return -static_cast <int> (e.GetErrorCode());
  374         }
  375         catch (std::exception &e)
  376         {
  377             SystemLog::WriteException (e);
  378             return -EINTR;
  379         }
  380         catch (...)
  381         {
  382             SystemLog::WriteException (UnknownException (SRC_POS));
  383             return -EINTR;
  384         }
  385     }
  386 
  387     shared_ptr <Buffer> FuseService::GetVolumeInfo ()
  388     {
  389         shared_ptr <Stream> stream (new MemoryStream);
  390 
  391         {
  392             ScopeLock lock (OpenVolumeInfoMutex);
  393 
  394             OpenVolumeInfo.Set (*MountedVolume);
  395             OpenVolumeInfo.SlotNumber = SlotNumber;
  396 
  397             OpenVolumeInfo.Serialize (stream);
  398         }
  399 
  400         ConstBufferPtr infoBuf = dynamic_cast <MemoryStream&> (*stream);
  401         shared_ptr <Buffer> outBuf (new Buffer (infoBuf.Size()));
  402         outBuf->CopyFrom (infoBuf);
  403 
  404         return outBuf;
  405     }
  406 
  407     const char *FuseService::GetVolumeImagePath ()
  408     {
  409 #ifdef TC_MACOSX
  410         return "/volume.dmg";
  411 #else
  412         return "/volume";
  413 #endif
  414     }
  415 
  416     uint64 FuseService::GetVolumeSize ()
  417     {
  418         if (!MountedVolume)
  419             throw NotInitialized (SRC_POS);
  420 
  421         return MountedVolume->GetSize();
  422     }
  423 
  424     void FuseService::Mount (shared_ptr <Volume> openVolume, VolumeSlotNumber slotNumber, const string &fuseMountPoint)
  425     {
  426         list <string> args;
  427         args.push_back (FuseService::GetDeviceType());
  428         args.push_back (fuseMountPoint);
  429 
  430 #ifdef TC_MACOSX
  431         args.push_back ("-o");
  432         args.push_back ("noping_diskarb");
  433         args.push_back ("-o");
  434         args.push_back ("nobrowse");
  435 
  436         if (getuid() == 0 || geteuid() == 0)
  437 #endif
  438         {
  439             args.push_back ("-o");
  440             args.push_back ("allow_other");
  441         }
  442 
  443         ExecFunctor execFunctor (openVolume, slotNumber);
  444         Process::Execute ("fuse", args, -1, &execFunctor);
  445 
  446         for (int t = 0; true; t++)
  447         {
  448             try
  449             {
  450                 if (FilesystemPath (fuseMountPoint + FuseService::GetControlPath()).GetType() == FilesystemPathType::File)
  451                     break;
  452             }
  453             catch (...)
  454             {
  455                 if (t > 50)
  456                     throw;
  457 
  458                 Thread::Sleep (100);
  459             }
  460         }
  461     }
  462 
  463     void FuseService::ReadVolumeSectors (const BufferPtr &buffer, uint64 byteOffset)
  464     {
  465         if (!MountedVolume)
  466             throw NotInitialized (SRC_POS);
  467 
  468         MountedVolume->ReadSectors (buffer, byteOffset);
  469     }
  470 
  471     void FuseService::ReceiveAuxDeviceInfo (const ConstBufferPtr &buffer)
  472     {
  473         shared_ptr <Stream> stream (new MemoryStream (buffer));
  474         Serializer sr (stream);
  475 
  476         ScopeLock lock (OpenVolumeInfoMutex);
  477         OpenVolumeInfo.VirtualDevice = sr.DeserializeString ("VirtualDevice");
  478         OpenVolumeInfo.LoopDevice = sr.DeserializeString ("LoopDevice");
  479     }
  480 
  481     void FuseService::SendAuxDeviceInfo (const DirectoryPath &fuseMountPoint, const DevicePath &virtualDevice, const DevicePath &loopDevice)
  482     {
  483         File fuseServiceControl;
  484         fuseServiceControl.Open (string (fuseMountPoint) + GetControlPath(), File::OpenWrite);
  485 
  486         shared_ptr <Stream> stream (new MemoryStream);
  487         Serializer sr (stream);
  488 
  489         sr.Serialize ("VirtualDevice", string (virtualDevice));
  490         sr.Serialize ("LoopDevice", string (loopDevice));
  491         fuseServiceControl.Write (dynamic_cast <MemoryStream&> (*stream));
  492     }
  493 
  494     void FuseService::WriteVolumeSectors (const ConstBufferPtr &buffer, uint64 byteOffset)
  495     {
  496         if (!MountedVolume)
  497             throw NotInitialized (SRC_POS);
  498 
  499         MountedVolume->WriteSectors (buffer, byteOffset);
  500     }
  501 
  502     void FuseService::OnSignal (int signal)
  503     {
  504         try
  505         {
  506             shared_ptr <VolumeInfo> volume = Core->GetMountedVolume (SlotNumber);
  507 
  508             if (volume)
  509                 Core->DismountVolume (volume, true);
  510         }
  511         catch (...) { }
  512 
  513         _exit (0);
  514     }
  515 
  516     void FuseService::ExecFunctor::operator() (int argc, char *argv[])
  517     {
  518         struct timeval tv;
  519         gettimeofday (&tv, NULL);
  520         FuseService::OpenVolumeInfo.SerialInstanceNumber = (uint64)tv.tv_sec * 1000000ULL + tv.tv_usec;
  521 
  522         FuseService::MountedVolume = MountedVolume;
  523         FuseService::SlotNumber = SlotNumber;
  524 
  525         FuseService::UserId = getuid();
  526         FuseService::GroupId = getgid();
  527 
  528         if (getenv ("SUDO_UID"))
  529         {
  530             try
  531             {
  532                 string s (getenv ("SUDO_UID"));
  533                 FuseService::UserId = static_cast <uid_t> (StringConverter::ToUInt64 (s));
  534 
  535                 if (getenv ("SUDO_GID"))
  536                 {
  537                     s = getenv ("SUDO_GID");
  538                     FuseService::GroupId = static_cast <gid_t> (StringConverter::ToUInt64 (s));
  539                 }
  540             }
  541             catch (...) { }
  542         }
  543 
  544         static fuse_operations fuse_service_oper;
  545 
  546         fuse_service_oper.access = fuse_service_access;
  547         fuse_service_oper.destroy = fuse_service_destroy;
  548         fuse_service_oper.getattr = fuse_service_getattr;
  549         fuse_service_oper.init = fuse_service_init;
  550         fuse_service_oper.open = fuse_service_open;
  551         fuse_service_oper.opendir = fuse_service_opendir;
  552         fuse_service_oper.read = fuse_service_read;
  553         fuse_service_oper.readdir = fuse_service_readdir;
  554         fuse_service_oper.write = fuse_service_write;
  555 
  556         // Create a new session
  557         setsid ();
  558 
  559         // Fork handler of termination signals
  560         SignalHandlerPipe.reset (new Pipe);
  561 
  562         int forkedPid = fork();
  563         throw_sys_if (forkedPid == -1);
  564 
  565         if (forkedPid == 0)
  566         {
  567             CloseMountedVolume();
  568 
  569             struct sigaction action;
  570             Memory::Zero (&action, sizeof (action));
  571             action.sa_handler = OnSignal;
  572 
  573             sigaction (SIGINT, &action, nullptr);
  574             sigaction (SIGQUIT, &action, nullptr);
  575             sigaction (SIGTERM, &action, nullptr);
  576 
  577             // Wait for the exit of the main service
  578             byte buf[1];
  579             if (read (SignalHandlerPipe->GetReadFD(), buf, sizeof (buf))) { } // Errors ignored
  580 
  581             _exit (0);
  582         }
  583 
  584         SignalHandlerPipe->GetWriteFD();
  585 
  586         _exit (fuse_main (argc, argv, &fuse_service_oper));
  587     }
  588 
  589     VolumeInfo FuseService::OpenVolumeInfo;
  590     Mutex FuseService::OpenVolumeInfoMutex;
  591     shared_ptr <Volume> FuseService::MountedVolume;
  592     VolumeSlotNumber FuseService::SlotNumber;
  593     uid_t FuseService::UserId;
  594     gid_t FuseService::GroupId;
  595     auto_ptr <Pipe> FuseService::SignalHandlerPipe;
  596 }