Repository navigation
Conversation
|
MountAllDeviceHostedVolumes does not catch VolumeAlreadyMounted. A device already mounted under another path now stops --auto-mount=devices after 10 s instead of being skipped. |
de268d1 to
5a39440
Compare
|
Both fixed in a second commit. A volume device held by a device-mapper device, or a volume file backing a loop device, is now refused before the lock is taken, which covers the deferred dm device after an emergency dismount with kernel crypto. A volume mounted under another path is refused at once, and |
5a39440 to
db4f54b
Compare
|
|
…open An emergency dismount lazily detaches the file systems. The FUSE service keeps running with the volume open until the last file on the detached file system is closed, but the volume is no longer in the mount table, so it could be mounted again and two services wrote to it. Once the volume is open, take an exclusive flock for it. The FUSE service inherits the descriptor and holds the lock until it exits; a second mount fails with "already mounted" meanwhile. Because a normally dismounted service may still be exiting, a busy lock is retried for up to 10 seconds. The lock is named after the device number, or the file system and inode numbers, that fstat reports for the opened volume, so it applies to the file actually served, whatever path leads to it. It is not taken on the volume file itself, whose locking is disabled to avoid remote file system issues. The lock files are created with openat in the root owned /var/run/veracrypt, which is opened without following symbolic links and checked through its descriptor. /var/run also exists on systems without /run. Without root or a usable lock directory, mounting works as before. Fixes veracrypt#1959
With kernel crypto, the volume is used by a device-mapper device, which an emergency dismount removes deferred. The FUSE service exits, so the volume lock was released while the device still used the volume, and the volume could be mounted again in another slot. Before taking the lock, refuse a volume device held by a device-mapper device, or a volume file backing a loop device. A volume mounted under another path, for example a device alias, made a second mount wait for the lock for 10 seconds. Refuse at once when a mounted volume is the same file or device. --auto-mount=devices skips such a device instead of stopping at it.
The volume lock and the kernel device check let mounting continue when they could not establish that the volume was unused: an unusable lock directory, an unexpected flock error, a sysfs or loop device that could not be inspected, or an fstat failing on a file opened with the requester's credentials, as FUSE checks the credentials of the calling process. A writable mount is now refused in these cases; a read-only one continues as before. A loop device that disappears during the check is still taken as not using the volume. The requester's process passes the device and inode of the file it opened, and the lock uses them for such files instead of fstat. The kernel device check is repeated once the lock is held: another mount of the volume may have finished, and been dismounted in an emergency, while this one was waiting for it. The lock descriptor is closed if an exception occurs before it is returned. The lock directory must belong to the user running VeraCrypt, root, and be writable only by it. CoreUnix::GetMountLockDirectory() gives its location, which the unprivileged mount test overrides, so that it uses the production locks instead of failing to create /var/run/veracrypt.
Tests/test_linux_emergency_dismount_remount.py checks no second mount while an emergency-detached service keeps the volume open against the installed package in the Linux workflow.
db4f54b to
a579445
Compare
Fixes #1959.
An emergency dismount lazily detaches the file systems, and the FUSE service keeps the volume open until the last file on the detached file system is closed, but the volume is no longer in the mount table. Once the volume is open, an exclusive
flockis taken for it and inherited by the FUSE service, which holds it until it exits; a second mount fails with "already mounted" meanwhile. A busy lock is retried for 10 s because a normally dismounted service may still be exiting.The lock is named after the device number, or the file system and inode numbers, that
fstatreports for the opened volume, so it applies to the file actually served whatever path leads to it. It is not taken on the volume file itself, whose locking is disabled for remote file systems. The lock files are created withopenatin the root owned/var/run/veracrypt(also present where/runis not), which is opened without following symbolic links and checked through its descriptor. Without root or a usable lock directory, mounting works as before. The lock files are not removed, to avoid the usual unlink race; they are small and on tmpfs. This addsFile::GetSystemHandle().A second commit covers kernel crypto, where the deferred device-mapper device keeps using the volume after the FUSE service has exited: before taking the lock, a volume device held by a device-mapper device, or a volume file backing a loop device (
CoreLinux::IsVolumeUsedByKernelDevice, using the existing loop helpers), is refused. A volume mounted under another path is refused at once instead of after the 10 s wait, and--auto-mount=devicesskips such a device instead of stopping. The lock directory handling is shared with #1966 (OpenMountLockFile).Tested:
Tests/test_linux_emergency_dismount_remount.py(new, run in the Linux workflow), with FUSE and with kernel crypto, and a mount through a symbolic link while the volume is mounted: passes on ubuntu-24.04 and ubuntu-26.04, https://github.com/flatstik/VeraCrypt/actions/runs/40582819859; with only the first commit, the kernel crypto remount succeeds and the mount through the link fails only after 10 s, https://github.com/flatstik/VeraCrypt/actions/runs/40582822189.--auto-mount=deviceschange is not covered by a test.The new test adds lines next to
test_mount_helper.pyin.github/workflows/build-linux.yml, as do the other PRs split from #1963, so whichever is merged later conflicts there; I will rebase it.Split from #1963, with #1968 (#1958), #1966 (#1960), #1964 (#1961), #1965 (#1962).