"Fossies" - the Fresh Open Source Software Archive

Member "src/Core/Unix/Linux/CoreLinux.cpp" (10 Oct 2018, 13197 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 "CoreLinux.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.22_Source_vs_1.23_Source.

    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 #include <fstream>
   14 #include <iomanip>
   15 #include <mntent.h>
   16 #include <stdio.h>
   17 #include <stdlib.h>
   18 #include <unistd.h>
   19 #include <sys/mount.h>
   20 #include <sys/wait.h>
   21 #include "CoreLinux.h"
   22 #include "Platform/SystemInfo.h"
   23 #include "Platform/TextReader.h"
   24 #include "Volume/EncryptionModeXTS.h"
   25 #include "Driver/Fuse/FuseService.h"
   26 #include "Core/Unix/CoreServiceProxy.h"
   27 
   28 namespace VeraCrypt
   29 {
   30     CoreLinux::CoreLinux ()
   31     {
   32     }
   33 
   34     CoreLinux::~CoreLinux ()
   35     {
   36     }
   37 
   38     DevicePath CoreLinux::AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const
   39     {
   40         list <string> loopPaths;
   41         loopPaths.push_back ("/dev/loop");
   42         loopPaths.push_back ("/dev/loop/");
   43         loopPaths.push_back ("/dev/.static/dev/loop");
   44 
   45         // On Fedora 23,"losetup -f" must be called first to create a default loop device
   46         list <string> args;
   47         args.push_back ("-f");
   48 
   49         try
   50         {
   51             Process::Execute ("losetup", args);
   52         }
   53         catch (...) { }
   54 
   55         for (int devIndex = 0; devIndex < 256; devIndex++)
   56         {
   57             string loopDev;
   58             foreach (const string &loopPath, loopPaths)
   59             {
   60                 loopDev = loopPath + StringConverter::ToSingle (devIndex);
   61                 if (FilesystemPath (loopDev).IsBlockDevice())
   62                     break;
   63             }
   64 
   65             if (loopDev.empty())
   66                 continue;
   67 
   68             list <string> args;
   69 
   70             list <string>::iterator readOnlyArg;
   71             if (readOnly)
   72             {
   73                 args.push_back ("-r");
   74                 readOnlyArg = --args.end();
   75             }
   76 
   77             args.push_back ("--");
   78             args.push_back (loopDev);
   79             args.push_back (filePath);
   80 
   81             try
   82             {
   83                 Process::Execute ("losetup", args);
   84                 return loopDev;
   85             }
   86             catch (ExecutedProcessFailed&)
   87             {
   88                 if (readOnly)
   89                 {
   90                     try
   91                     {
   92                         args.erase (readOnlyArg);
   93                         Process::Execute ("losetup", args);
   94                         return loopDev;
   95                     }
   96                     catch (ExecutedProcessFailed&) { }
   97                 }
   98             }
   99         }
  100 
  101         throw LoopDeviceSetupFailed (SRC_POS, wstring (filePath));
  102     }
  103 
  104     void CoreLinux::DetachLoopDevice (const DevicePath &devicePath) const
  105     {
  106         list <string> args;
  107         args.push_back ("-d");
  108         args.push_back (devicePath);
  109 
  110         for (int t = 0; true; t++)
  111         {
  112             try
  113             {
  114                 Process::Execute ("losetup", args);
  115                 break;
  116             }
  117             catch (ExecutedProcessFailed&)
  118             {
  119                 if (t > 5)
  120                     throw;
  121                 Thread::Sleep (200);
  122             }
  123         }
  124     }
  125 
  126     void CoreLinux::DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const
  127     {
  128         string devPath = mountedVolume->VirtualDevice;
  129 
  130         if (devPath.find ("/dev/mapper/veracrypt") != 0)
  131             throw NotApplicable (SRC_POS);
  132 
  133         size_t devCount = 0;
  134         while (FilesystemPath (devPath).IsBlockDevice())
  135         {
  136             list <string> dmsetupArgs;
  137             dmsetupArgs.push_back ("remove");
  138             dmsetupArgs.push_back (StringConverter::Split (devPath, "/").back());
  139 
  140             for (int t = 0; true; t++)
  141             {
  142                 try
  143                 {
  144                     Process::Execute ("dmsetup", dmsetupArgs);
  145                     break;
  146                 }
  147                 catch (...)
  148                 {
  149                     if (t > 20)
  150                         throw;
  151 
  152                     Thread::Sleep (100);
  153                 }
  154             }
  155 
  156             for (int t = 0; FilesystemPath (devPath).IsBlockDevice() && t < 20; t++)
  157             {
  158                 Thread::Sleep (100);
  159             }
  160 
  161             devPath = string (mountedVolume->VirtualDevice) + "_" + StringConverter::ToSingle (devCount++);
  162         }
  163     }
  164 
  165     HostDeviceList CoreLinux::GetHostDevices (bool pathListOnly) const
  166     {
  167         HostDeviceList devices;
  168         TextReader tr ("/proc/partitions");
  169 
  170         string line;
  171         while (tr.ReadLine (line))
  172         {
  173             vector <string> fields = StringConverter::Split (line);
  174 
  175             if (fields.size() != 4
  176                 || fields[3].find ("loop") == 0 // skip loop devices
  177                 || fields[3].find ("cloop") == 0
  178                 || fields[3].find ("ram") == 0  // skip RAM devices
  179                 || fields[3].find ("dm-") == 0  // skip device mapper devices
  180                 || fields[2] == "1"             // skip extended partitions
  181                 )
  182                 continue;
  183 
  184             try
  185             {
  186                 StringConverter::ToUInt32 (fields[0]);
  187             }
  188             catch (...)
  189             {
  190                 continue;
  191             }
  192 
  193             try
  194             {
  195                 make_shared_auto (HostDevice, hostDevice);
  196 
  197                 hostDevice->Path = string (fields[3].find ("/dev/") == string::npos ? "/dev/" : "") + fields[3];
  198 
  199                 if (!pathListOnly)
  200                 {
  201                     hostDevice->Size = StringConverter::ToUInt64 (fields[2]) * 1024;
  202                     hostDevice->MountPoint = GetDeviceMountPoint (hostDevice->Path);
  203                     hostDevice->SystemNumber = 0;
  204                 }
  205 
  206                 try
  207                 {
  208                     StringConverter::GetTrailingNumber (fields[3]);
  209                     if (devices.size() > 0)
  210                     {
  211                         HostDevice &prevDev = **--devices.end();
  212                         if (string (hostDevice->Path).find (prevDev.Path) == 0)
  213                         {
  214                             prevDev.Partitions.push_back (hostDevice);
  215                             continue;
  216                         }
  217                     }
  218                 }
  219                 catch (...) { }
  220 
  221                 devices.push_back (hostDevice);
  222                 continue;
  223             }
  224             catch (...)
  225             {
  226                 continue;
  227             }
  228         }
  229 
  230         return devices;
  231     }
  232 
  233     MountedFilesystemList CoreLinux::GetMountedFilesystems (const DevicePath &devicePath, const DirectoryPath &mountPoint) const
  234     {
  235         MountedFilesystemList mountedFilesystems;
  236         DevicePath realDevicePath = devicePath;
  237 
  238         if (!devicePath.IsEmpty())
  239         {
  240             char *resolvedPath = realpath (string (devicePath).c_str(), NULL);
  241             if (resolvedPath)
  242             {
  243                 realDevicePath = resolvedPath;
  244                 free (resolvedPath);
  245             }
  246         }
  247 
  248         FILE *mtab = fopen ("/etc/mtab", "r");
  249 
  250         if (!mtab)
  251             mtab = fopen ("/proc/mounts", "r");
  252 
  253         throw_sys_sub_if (!mtab, "/proc/mounts");
  254         finally_do_arg (FILE *, mtab, { fclose (finally_arg); });
  255 
  256         static Mutex mutex;
  257         ScopeLock sl (mutex);
  258 
  259         struct mntent *entry;
  260         while ((entry = getmntent (mtab)) != nullptr)
  261         {
  262             make_shared_auto (MountedFilesystem, mf);
  263 
  264             if (entry->mnt_fsname)
  265                 mf->Device = DevicePath (entry->mnt_fsname);
  266             else
  267                 continue;
  268 
  269             if (entry->mnt_dir)
  270                 mf->MountPoint = DirectoryPath (entry->mnt_dir);
  271 
  272             if (entry->mnt_type)
  273                 mf->Type = entry->mnt_type;
  274 
  275             if ((devicePath.IsEmpty() || devicePath == mf->Device || realDevicePath == mf->Device) && (mountPoint.IsEmpty() || mountPoint == mf->MountPoint))
  276                 mountedFilesystems.push_back (mf);
  277         }
  278 
  279         return mountedFilesystems;
  280     }
  281 
  282     void CoreLinux::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
  283     {
  284         bool fsMounted = false;
  285 
  286         try
  287         {
  288             if (!FilesystemSupportsUnixPermissions (devicePath))
  289             {
  290                 stringstream userMountOptions;
  291                 userMountOptions << "uid=" << GetRealUserId() << ",gid=" << GetRealGroupId() << ",umask=077" << (!systemMountOptions.empty() ? "," : "");
  292 
  293                 CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, userMountOptions.str() + systemMountOptions);
  294                 fsMounted = true;
  295             }
  296         }
  297         catch (...) { }
  298 
  299         if (!fsMounted)
  300             CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, systemMountOptions);
  301     }
  302 
  303     void CoreLinux::MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const
  304     {
  305         bool xts = (typeid (*volume->GetEncryptionMode()) == typeid (EncryptionModeXTS));
  306         bool algoNotSupported = (typeid (*volume->GetEncryptionAlgorithm()) == typeid (GOST89))
  307             || (typeid (*volume->GetEncryptionAlgorithm()) == typeid (Kuznyechik))
  308             || (typeid (*volume->GetEncryptionAlgorithm()) == typeid (CamelliaKuznyechik))
  309             || (typeid (*volume->GetEncryptionAlgorithm()) == typeid (KuznyechikTwofish))
  310             || (typeid (*volume->GetEncryptionAlgorithm()) == typeid (KuznyechikAES))
  311             || (typeid (*volume->GetEncryptionAlgorithm()) == typeid (KuznyechikSerpentCamellia));
  312 
  313         if (options.NoKernelCrypto
  314             || !xts
  315             || algoNotSupported
  316             || volume->IsEncryptionNotCompleted ()
  317             || volume->GetProtectionType() == VolumeProtection::HiddenVolumeReadOnly)
  318         {
  319             throw NotApplicable (SRC_POS);
  320         }
  321 
  322         if (!SystemInfo::IsVersionAtLeast (2, 6, xts ? 24 : 20))
  323             throw NotApplicable (SRC_POS);
  324 
  325         // Load device mapper kernel module
  326         list <string> execArgs;
  327         foreach (const string &dmModule, StringConverter::Split ("dm_mod dm-mod dm"))
  328         {
  329             execArgs.clear();
  330             execArgs.push_back (dmModule);
  331 
  332             try
  333             {
  334                 Process::Execute ("modprobe", execArgs);
  335                 break;
  336             }
  337             catch (...) { }
  338         }
  339 
  340         bool loopDevAttached = false;
  341         bool nativeDevCreated = false;
  342         bool filesystemMounted = false;
  343 
  344         // Attach volume to loopback device if required
  345         VolumePath volumePath = volume->GetPath();
  346         if (!volumePath.IsDevice())
  347         {
  348             volumePath = AttachFileToLoopDevice (volumePath, options.Protection == VolumeProtection::ReadOnly);
  349             loopDevAttached = true;
  350         }
  351 
  352         string nativeDevPath;
  353 
  354         try
  355         {
  356             // Create virtual device using device mapper
  357             size_t nativeDevCount = 0;
  358             size_t secondaryKeyOffset = volume->GetEncryptionMode()->GetKey().Size();
  359             size_t cipherCount = volume->GetEncryptionAlgorithm()->GetCiphers().size();
  360 
  361             foreach_reverse_ref (const Cipher &cipher, volume->GetEncryptionAlgorithm()->GetCiphers())
  362             {
  363                 stringstream dmCreateArgs;
  364                 dmCreateArgs << "0 " << volume->GetSize() / ENCRYPTION_DATA_UNIT_SIZE << " crypt ";
  365 
  366                 // Mode
  367                 dmCreateArgs << StringConverter::ToLower (StringConverter::ToSingle (cipher.GetName())) << (xts ? (SystemInfo::IsVersionAtLeast (2, 6, 33) ? "-xts-plain64 " : "-xts-plain ") : "-lrw-benbi ");
  368 
  369                 size_t keyArgOffset = dmCreateArgs.str().size();
  370                 dmCreateArgs << setw (cipher.GetKeySize() * (xts ? 4 : 2) + (xts ? 0 : 16 * 2)) << 0 << setw (0);
  371 
  372                 // Sector and data unit offset
  373                 uint64 startSector = volume->GetLayout()->GetDataOffset (volume->GetHostSize()) / ENCRYPTION_DATA_UNIT_SIZE;
  374 
  375                 dmCreateArgs << ' ' << (xts ? startSector + volume->GetEncryptionMode()->GetSectorOffset() : 0) << ' ';
  376                 if (nativeDevCount == 0)
  377                     dmCreateArgs << string (volumePath) << ' ' << startSector;
  378                 else
  379                     dmCreateArgs << nativeDevPath << " 0";
  380 
  381                 SecureBuffer dmCreateArgsBuf (dmCreateArgs.str().size());
  382                 dmCreateArgsBuf.CopyFrom (ConstBufferPtr ((byte *) dmCreateArgs.str().c_str(), dmCreateArgs.str().size()));
  383 
  384                 // Keys
  385                 const SecureBuffer &cipherKey = cipher.GetKey();
  386                 secondaryKeyOffset -= cipherKey.Size();
  387                 ConstBufferPtr secondaryKey = volume->GetEncryptionMode()->GetKey().GetRange (xts ? secondaryKeyOffset : 0, xts ? cipherKey.Size() : 16);
  388 
  389                 SecureBuffer hexStr (3);
  390                 for (size_t i = 0; i < cipherKey.Size(); ++i)
  391                 {
  392                     sprintf ((char *) hexStr.Ptr(), "%02x", (int) cipherKey[i]);
  393                     dmCreateArgsBuf.GetRange (keyArgOffset + i * 2, 2).CopyFrom (hexStr.GetRange (0, 2));
  394 
  395                     sprintf ((char *) hexStr.Ptr(), "%02x", (int) secondaryKey[i]);
  396                     dmCreateArgsBuf.GetRange (keyArgOffset + cipherKey.Size() * 2 + i * 2, 2).CopyFrom (hexStr.GetRange (0, 2));
  397                 }
  398 
  399                 stringstream nativeDevName;
  400                 nativeDevName << "veracrypt" << options.SlotNumber;
  401 
  402                 if (nativeDevCount != cipherCount - 1)
  403                     nativeDevName << "_" << cipherCount - nativeDevCount - 2;
  404 
  405                 nativeDevPath = "/dev/mapper/" + nativeDevName.str();
  406 
  407                 execArgs.clear();
  408                 execArgs.push_back ("create");
  409                 execArgs.push_back (nativeDevName.str());
  410 
  411                 Process::Execute ("dmsetup", execArgs, -1, nullptr, &dmCreateArgsBuf);
  412 
  413                 // Wait for the device to be created
  414                 for (int t = 0; true; t++)
  415                 {
  416                     try
  417                     {
  418                         FilesystemPath (nativeDevPath).GetType();
  419                         break;
  420                     }
  421                     catch (...)
  422                     {
  423                         if (t > 20)
  424                             throw;
  425 
  426                         Thread::Sleep (100);
  427                     }
  428                 }
  429 
  430                 nativeDevCreated = true;
  431                 ++nativeDevCount;
  432             }
  433 
  434             // Test whether the device mapper is able to read and decrypt the last sector
  435             SecureBuffer lastSectorBuf (volume->GetSectorSize());
  436             uint64 lastSectorOffset = volume->GetSize() - volume->GetSectorSize();
  437 
  438             File nativeDev;
  439             nativeDev.Open (nativeDevPath);
  440             nativeDev.ReadAt (lastSectorBuf, lastSectorOffset);
  441 
  442             SecureBuffer lastSectorBuf2 (volume->GetSectorSize());
  443             volume->ReadSectors (lastSectorBuf2, lastSectorOffset);
  444 
  445             if (memcmp (lastSectorBuf.Ptr(), lastSectorBuf2.Ptr(), volume->GetSectorSize()) != 0)
  446                 throw KernelCryptoServiceTestFailed (SRC_POS);
  447 
  448             // Mount filesystem
  449             if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty())
  450             {
  451                 MountFilesystem (nativeDevPath, *options.MountPoint,
  452                     StringConverter::ToSingle (options.FilesystemType),
  453                     options.Protection == VolumeProtection::ReadOnly,
  454                     StringConverter::ToSingle (options.FilesystemOptions));
  455 
  456                 filesystemMounted = true;
  457             }
  458 
  459             FuseService::SendAuxDeviceInfo (auxMountPoint, nativeDevPath, volumePath);
  460         }
  461         catch (...)
  462         {
  463             try
  464             {
  465                 if (filesystemMounted)
  466                     DismountFilesystem (*options.MountPoint, true);
  467             }
  468             catch (...) { }
  469 
  470             try
  471             {
  472                 if (nativeDevCreated)
  473                 {
  474                     make_shared_auto (VolumeInfo, vol);
  475                     vol->VirtualDevice = nativeDevPath;
  476                     DismountNativeVolume (vol);
  477                 }
  478             }
  479             catch (...) { }
  480 
  481             try
  482             {
  483                 if (loopDevAttached)
  484                     DetachLoopDevice (volumePath);
  485             }
  486             catch (...) { }
  487 
  488             throw;
  489         }
  490     }
  491 
  492     auto_ptr <CoreBase> Core (new CoreServiceProxy <CoreLinux>);
  493     auto_ptr <CoreBase> CoreDirect (new CoreLinux);
  494 }