Skip to content

Commit b2b28d5

Browse files
committed
Linux: release only the volume's own loop and device-mapper devices
Unmounting released the loop device and device-mapper devices recorded at mount time, by name. After a dismount that failed partway, for example on a busy auxiliary FUSE mount, these names could be reused by unrelated objects, which the listing then showed as the volume's and a retry, emergency cleanup, filesystem check or auto-dismount released. Without kernel cryptography, the loop device, which carries the decrypted volume, was also released while the filesystem was mounted elsewhere or the device was held open. A failed mount could remove a pre-existing device-mapper device of the same name, and a failed cascade mount could leave its layers and loop device behind. Each destructive step now acts only on a device verified to belong to the volume. A loop device must be bound to the container or volume image (LOOP_GET_STATUS64). Device-mapper devices get the UUID VERACRYPT-<serial>-<name> and are removed by UUID; those of earlier versions, which have none, are verified through their sysfs slaves, and the dismount fails, saying why, if that is not possible. Emergency cleanup is not offered then, as it would hide the volume but leave its devices. While the filesystem is mounted elsewhere, the dismount fails and keeps the volume's devices. With kernel cryptography, the loop device is marked for autoclear as soon as it is attached and verified, so the kernel detaches it once device-mapper releases it; a process holding it open sees only ciphertext and does not fail the dismount. Without kernel cryptography, the dismount also fails while the loop device is held open. Dismount, emergency cleanup, filesystem check and the listing re-read the volume's devices from its auxiliary mount, and the English emergency warning mentions these causes. Add Tests/test_linux_loop_identity.py, covering these cases with and without kernel cryptography, and with --legacy-binary, volumes mounted by an earlier version. All 89 checks pass, as do the 11 added by --legacy-binary 1.26.29; 1.26.29 itself fails 21 of the 89.
1 parent 4b3d38e commit b2b28d5

7 files changed

Lines changed: 1337 additions & 202 deletions

File tree

‎Tests/test_linux_loop_identity.py‎

Lines changed: 549 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Common/Language.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1666,7 +1666,7 @@
16661666
<entry lang="en" key="LINUX_PREF_MOUNT_NTFS_WITH_KERNEL_DRIVER">Mount NTFS volumes with an in-kernel Linux driver</entry>
16671667
<entry lang="en" key="LINUX_PREF_MOUNT_NTFS_WITH_KERNEL_DRIVER_HELP">Linux only. When enabled and no explicit filesystem type was supplied, VeraCrypt probes the decrypted virtual device with blkid -p and mounts detected NTFS filesystems with an available in-kernel NTFS driver, bypassing mount helpers such as ntfs-3g. VeraCrypt uses ntfs when it is positively identified as a modern read/write driver or expected on Linux 7.1 or later, and otherwise uses ntfs3. If NTFS detection fails, VeraCrypt uses the normal automatic filesystem selection. If no supported in-kernel NTFS driver is available or loadable, mounting fails. This opt-in option can avoid suspend or hibernate hangs caused by frozen user-space FUSE filesystems.</entry>
16681668
<entry lang="en" key="LINUX_KERNEL_NTFS_DRIVER_UNAVAILABLE">No supported in-kernel NTFS driver is available or loadable. To use the system default NTFS backend, disable the NTFS kernel-driver preference or do not request kernel NTFS explicitly.</entry>
1669-
<entry lang="en" key="LINUX_EMERGENCY_UNMOUNT_WARNING">Normal unmount of volume {0} failed. This can happen when applications still have files or directories open on the volume, or when the backing device was disconnected and the mount became stale.\n\nIf the device is still connected, choose No, close applications using the volume, and try unmounting again.\n\nIf the device was disconnected or the mount is stale, VeraCrypt can attempt emergency cleanup by lazy-detaching the filesystem and removing or scheduling removal of VeraCrypt kernel objects. Pending writes may have failed, data may be lost, and cleanup may remain pending until applications close open files. Check the filesystem with fsck or the appropriate repair tool before using it again.\n\nContinue?</entry>
1669+
<entry lang="en" key="LINUX_EMERGENCY_UNMOUNT_WARNING">Normal unmount of volume {0} failed. This can happen when applications still have files or directories open on the volume, when the volume's filesystem is also mounted elsewhere (for example, a bind mount or a mount in another mount namespace), when another process has the volume's device open, or when the backing device was disconnected and the mount became stale.\n\nIf the device is still connected, choose No, close applications using the volume, unmount any other mounts of its filesystem, and try unmounting again.\n\nIf the device was disconnected or the mount is stale, VeraCrypt can attempt emergency cleanup by lazy-detaching the filesystem and removing or scheduling removal of VeraCrypt kernel objects. Pending writes may have failed, data may be lost, and cleanup may remain pending until applications close open files. Check the filesystem with fsck or the appropriate repair tool before using it again.\n\nContinue?</entry>
16701670
<entry lang="en" key="LINUX_EMERGENCY_UNMOUNTED">Emergency cleanup for volume {0} has been initiated. If the volume was disconnected, the mount was stale, or there were pending writes, check the filesystem with fsck or the appropriate repair tool before using it again.</entry>
16711671
<entry lang="en" key="FORMAT_STAGE_WRITING_DATA">Creating volume data. Please wait.</entry>
16721672
<entry lang="en" key="FORMAT_STAGE_WRITING_BACKUP_HEADER">Finalizing volume creation: writing backup header.</entry>

‎src/Core/Unix/CoreUnix.cpp‎

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,17 @@ namespace VeraCrypt
306306
#endif
307307
catch (NotApplicable &) { }
308308

309-
// Earlier versions recorded the host device of a device-hosted volume mounted with Linux kernel cryptography as its loop device
310-
if (!mountedVolume->LoopDevice.IsEmpty() && wstring (mountedVolume->LoopDevice) != wstring (mountedVolume->Path))
309+
// On Linux, DismountNativeVolume detaches the loop device once it is verified to belong to the volume
310+
#ifndef TC_LINUX
311+
if (!mountedVolume->LoopDevice.IsEmpty())
311312
{
312313
try
313314
{
314315
DetachLoopDevice (mountedVolume->LoopDevice);
315316
}
316317
catch (ExecutedProcessFailed&) { }
317318
}
319+
#endif
318320

319321
if (syncVolumeInfo || mountedVolume->Protection == VolumeProtection::HiddenVolumeReadOnly)
320322
{
@@ -411,25 +413,6 @@ namespace VeraCrypt
411413
firstException.reset (e.CloneNew());
412414
}
413415

414-
// Earlier versions recorded the host device of a device-hosted volume mounted with kernel cryptography as its loop device
415-
if (!mountedVolume->LoopDevice.IsEmpty() && wstring (mountedVolume->LoopDevice) != wstring (mountedVolume->Path))
416-
{
417-
try
418-
{
419-
DetachLoopDevice (mountedVolume->LoopDevice);
420-
}
421-
catch (ExecutedProcessFailed &e)
422-
{
423-
if (IsLoopDeviceAttached (mountedVolume->LoopDevice) && !firstException.get())
424-
firstException.reset (e.CloneNew());
425-
}
426-
catch (Exception &e)
427-
{
428-
if (!firstException.get())
429-
firstException.reset (e.CloneNew());
430-
}
431-
}
432-
433416
if (!mountedVolume->AuxMountPoint.IsEmpty())
434417
{
435418
bool auxMountPointMounted = true;
@@ -725,16 +708,16 @@ namespace VeraCrypt
725708
mountedVol->AuxMountPoint = mf.MountPoint;
726709

727710
#ifndef TC_MACOSX
711+
// Recorded devices may have been released and reused since
712+
UpdateMountedVolumeInfo (mountedVol);
713+
728714
if (mountedVol->MountPoint.IsEmpty() && !mountedVol->VirtualDevice.IsEmpty())
729715
{
730716
MountedFilesystemList mpl = GetMountedFilesystems (mountedVol->VirtualDevice);
731717

732718
if (mpl.size() > 0)
733719
mountedVol->MountPoint = mpl.front()->MountPoint;
734720
}
735-
736-
if (mountedVol->MountPoint.IsEmpty() || mountedVol->VirtualDevice.IsEmpty())
737-
UpdateMountedVolumeInfo (mountedVol);
738721
#endif
739722

740723
volumes.push_back (mountedVol);

‎src/Core/Unix/CoreUnix.h‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ namespace VeraCrypt
6363
#ifdef TC_LINUX
6464
virtual void DismountFilesystemLazy (const DirectoryPath &mountPoint) const;
6565
virtual void DismountNativeVolumeDeferred (shared_ptr <VolumeInfo> mountedVolume) const { DismountNativeVolume (mountedVolume); }
66-
virtual bool IsLoopDeviceAttached (const DevicePath &devicePath) const { return devicePath.IsBlockDevice(); }
6766
#endif
6867
virtual bool FilesystemSupportsUnixPermissions (const DevicePath &devicePath) const;
6968
virtual string GetDefaultMountPointPrefix () const;

0 commit comments

Comments
 (0)