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
|
|
db4f54b to
a579445
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Critical gaps in loop-device identity locking and backing-file verification can still permit two writable mounts of the same container.
5 open issues
Unify locks for loop devices and backing container files · New Verify loop backing against the locked open file · New Limit loop backing queries to relevant kernel users · New Inspect bound loops through supported device-node layouts · New Resolve executable overrides before changing directories · New
What changed in this PR
This PR adds Linux safeguards against remounting volumes still in use after an emergency dismount, addressing #1959 in the Unix mounting code.
Changes:
- Adds volume-identity locks held by the FUSE service and checks for lingering kernel-device use.
- Preserves requester-derived file identities and skips already-mounted devices during automatic mounting.
- Adds remount regression tests and integrates them into the Linux workflow.
| File | Description |
|---|---|
Tests/test_linux_emergency_dismount_remount.py |
Tests emergency remounts with FUSE and kernel crypto, plus alternate paths. |
Tests/linux_mount_read_only_test.cpp |
Supplies a writable lock directory for unprivileged tests. |
Tests/linux_mount_points_test.cpp |
Supplies a test-local lock directory. |
src/Platform/Unix/RequesterAccess.cpp |
Returns device and inode identity from the requester helper. |
src/Platform/Unix/File.cpp |
Adds requester-aware file identity lookup. |
src/Platform/File.h |
Exposes handle/stat access and stores requester-derived identity. |
src/Main/UserInterface.cpp |
Skips already-mounted volumes during device auto-mounting. |
src/Core/Unix/Linux/CoreLinux.h |
Declares the kernel-device usage check. |
src/Core/Unix/Linux/CoreLinux.cpp |
Checks device-mapper holders and loop-device backing files. |
src/Core/Unix/CoreUnix.h |
Adds kernel-usage and lock-directory hooks. |
src/Core/Unix/CoreUnix.cpp |
Adds volume-identity locking, busy-lock retries, and alias checks. |
.github/workflows/build-linux.yml |
Triggers and runs the new Linux regression test. |
Review effort: Max
|
Will fix these based on suggestions latest on sunday. |
…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.
A volume mounted through a loop device took a lock unrelated to the lock of the same container mounted as a file, so an emergency dismounted file could be attached to a loop device and mounted a second time. The lock and the kernel user check now apply to the backing of the opened loop device, a file or a block device. A chain of loop devices is not followed, which refuses a writable mount; a partition of a loop device stays separate. Only loop devices held by device-mapper are queried for their backing file: the query reaches the file system of that file, so an unrelated loop device could fail or block every writable mount of a file. Their nodes are found in the layouts that AttachFileToLoopDevice supports and verified by the device number from sysfs; one that is still held without a usable node refuses the mount. MountVolumeNative verifies the loop device against the opened and locked file, not a new lookup of its path. The test resolves the executable once, as it runs commands in its work directory, and covers a detached service of a file against its loop device, and a deferred mapping on a loop device against its file.
1bf6fa9 to
89d5532
Compare
|
While I appreciate that the bug I reported is getting attention, this does not look like a reasonable fix at all anymore, but rather like complete AI slop with zero engineering behind it. This is a rare edge case to begin with and I would rather see the bug remain then watch this getting merged This goes for quite a few recent PRs and I am starting to worry what gets merged into veracrypt |
Issue #1982 is about locking the existing Windows option, and #1983 does that. I vibecoded the #1984 if it's wanted for the Unix side too. I am fully aware that user-process version would protect weakly and this is the result. Luckily, I am not the one who does the decision for merging and I'm just as happy if this is closed or merged or used as a startpoint for something else. If people really want something like this, they can use the code for their own amusement by compiling themselves. I'm also fully aware that maintenance of this is ridiculous. I'd use USBguard instead. |


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. A writable mount is refused when the lock cannot be taken; a read-only mount goes on without it. 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 held by one (
CoreLinux::IsVolumeUsedByKernelDevice), is refused; a writable mount is also refused if such a device cannot be inspected. Only loop devices held by device-mapper are queried, so an unrelated loop device cannot fail or block a mount. 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. A whole loop device takes the identity of its backing (GetVolumeIdentity), so a loop device and its file conflict; a loop chain is not followed, which refuses a writable mount, and a partition of a loop device stays separate. 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 and the alternate loop node layouts are 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).