Prefer sudo when available and fall back to doas on Unix. Run doas authentication through a PTY while keeping service communication on stdin/stdout pipes, and use a no-fork service mode for the doas path.
Keep doas authentication terminal descriptors close-on-exec and close the slave descriptor after attaching it as the controlling terminal. Preserve startup diagnostics through stderr until service synchronization completes, then redirect no-fork service stderr away from the closed parent pipe.
Use noninteractive privilege-helper auth checks for both sudo and doas so cached, nopass, or persisted sessions do not need an unnecessary VeraCrypt password prompt. Keep the PTY password path for doas when authentication is required.
Use a shared Unix DOAS_USER helper for FUSE and mount ownership, backed by getpwnam_r and guarded so non-OpenBSD platforms only trust it for VeraCrypt's internal doas no-fork service path. Detach asynchronous child-reaper threads to avoid leaking joinable pthread handles.
Keep the historical auto-mount behavior as the first attempt when the user did not request a filesystem type. If that mount fails on Linux, detect the filesystem with blkid and retry only for FAT-family types that minimal mount implementations may not auto-probe.
Leave explicit filesystem types and NTFS kernel-driver resolution unchanged.
CoreMacOSX::CheckFilesystem() ignored both its mountedVolume and repair
arguments and always just launched Disk Utility.app, so the "Check
Filesystem" and "Repair Filesystem" menu items behaved identically and
neither acted on the mounted volume. On Linux/BSD the same operation runs
fsck and honors the flag (passing -n only when repair is false).
Run diskutil on the VeraCrypt virtual device, choosing verifyVolume or
repairVolume per the flag (diskutil unmounts the inner filesystem itself
as needed). The Core layer has no GUI, so the result is shown in a
Terminal window via a temporary .command script; it falls back to
launching Disk Utility.app when no virtual device is available.
Run the macOS check in the unprivileged application process. VeraCrypt does
not need to create or launch the helper script from the elevated core
service: diskutil operates on the mounted virtual device and macOS handles
any device authorization requirements. Once a device-hosted mount has
started the elevated core service, every later service request is routed to
that root process. There it would create the helper script as root (0700)
and open a Terminal in the GUI session that the user could neither read nor
execute. CoreServiceProxy::CheckFilesystem now invokes the core
implementation directly on macOS instead of sending a service request, so
the script is always owned by the GUI user.
The device path is strictly validated as /dev/[r]diskN[sM] before being
single-quoted into the command. The helper script is created securely in
the per-user temp directory via mkstemps() (atomic O_EXCL/0600, fchmod
0700 by descriptor, close() checked for deferred write errors, unlinked on
any failure) rather than at a predictable, enumerable path in the
world-writable /tmp, guarding against a symlink/race on the executed
script. A trap removes the script on exit even if the window is closed
early, and it is also unlinked if launching Terminal fails. The script
captures $? so diskutil's result, including failures, is shown before the
script exits.
Replace the macOS pre-check message (which still told the user Disk
Utility would open and to pick Verify/Repair manually) with check- and
repair-specific text describing the new automatic diskutil flow.
Seed the two new strings into all translation files with the English
text so the XML key-completeness check passes; localization can follow.
Co-authored-by: Damian Rickard <damian@rickard.us>
Separate sudo authentication success from elevated request execution state by acknowledging when the elevated core service starts successfully.
Once that channel is available, propagate later failures instead of showing repeated administrator password dialogs. Initialize the sudo dummy-password flag consistently on macOS, avoiding an uninitialized read of UseDummySudoPassword.
Register admin-password cleanup before elevation attempts so plaintext sudo credentials are erased on early-return and post-sudo failure paths.
References #1788.
The hdiutil `-plist` output used for mount/dismount device discovery
(MountAuxVolumeImage and UpdateMountedVolumeInfo) was parsed with a
hand-rolled string scanner that assumed the value always follows the
requested key and that <key>/<string> pairs appear in a fixed order.
Replace it with the CoreFoundation property-list API
(CFPropertyListCreateWithData + dictionary/array navigation), which is
correct by construction and robust to hdiutil output ordering/variation.
An RAII helper (CFHolder) ensures CFRelease on every path.
Behavior is preserved: prefer the system-entity that carries a
mount-point, otherwise fall back to the first dev-entry, and match disk
images by normalized image-path. CoreFoundation is already linked on
macOS (via Cocoa), so no build changes are needed.
Verified end-to-end on Apple Silicon: mounting parses `hdiutil attach`
output and dismount parses `hdiutil info` output correctly.
Co-authored-by: Damian Rickard <damian@rickard.us>
The privileged CoreService handler for SetFileOwnerRequest passed the
client-supplied path straight to chown() as root with no validation --
unlike the adjacent APFS formatter handler, which strictly validates its
device argument. Every legitimate macOS caller of the elevated
SetFileOwner targets a real disk device node (/dev/[r]diskN[sM]), so a
crafted IPC request, or a symlink planted at the target, could otherwise
make the root process change ownership of an arbitrary path.
Validate the target service-side: require the strict device-path form
already used by the formatter, and lstat() it to confirm a block or
character device (rejecting symlinks rather than following them) before
the chown.
Co-authored-by: Damian Rickard <damian@rickard.us>
On Unix and macOS, the hidden volume wizard estimates the available space for non-FAT outer filesystems using statvfs(). The previous calculation used f_bsize with f_bavail, which can overstate available bytes on macOS exFAT because f_bsize may be the preferred I/O size instead of the fragment size associated with the block counts.
Use f_frsize when it is reported, fall back to f_bsize, and clamp the non-FAT estimate to the actual outer VeraCrypt data size before applying the existing 80% safety heuristic.
Also harden hidden volume creation in both the cross-platform VolumeCreator path and the Windows/common formatting path by rejecting sizes that would exceed the hidden host data area and overlap volume header space.
Fixes#1037
CentOS 6 builds VeraCrypt with GCC 4.4.7 and -std=c++0x. That compiler does not support range-based for loops, and its libstdc++ does not provide std::string::back() or std::string::pop_back().
Avoid those constructs in the affected Unix/Linux code paths: use VeraCrypt's existing foreach helper when iterating PKCS#11 object handles, and use indexing plus erase() when trimming trailing slashes from PATH entries.
This keeps the code valid for newer Linux toolchains while restoring compatibility with the CentOS 6 build environment.
VeraCrypt derives the real (non-root) user from SUDO_UID/SUDO_GID
to set default mount-point ownership and the FUSE service access
filter. On OpenBSD, privileged commands are normally run through doas,
which exposes the invoking login name via DOAS_USER and does not set
the sudo variables. As a result, VeraCrypt launched through doas
attributes both to root instead of the invoking user.
When the sudo identity variables are absent, resolve DOAS_USER through
the password database and use that uid/gid for default mount-point
ownership and the VeraCrypt FUSE service access filter. sudo behavior
is unchanged.
This is a correctness fix for the doas launch path. It is not confirmed
to resolve the non-root ext2fs EACCES reported in the linked issues:
that failure occurs at the ext2fs layer reached through vnd, whose
backing-image I/O runs as root and is therefore already permitted by
the access filter.
Refs #1589.
Refs #1593.
OpenBSD device length detection was returning the raw disk sector count from DIOCGPDINFO directly. That value is not bytes and it describes the physical/default disk label, which caused VeraCrypt to expose an incorrectly sized FUSE backing image through vnd for device-hosted volumes.
Use the current disklabel from DIOCGDINFO, derive the opened partition from the device minor number, and return the selected partition size in bytes. Keep the raw c partition on the whole-disk path by using DL_GETDSIZE there.
Also reject sector-misaligned device-hosted sizes during volume creation so new malformed OpenBSD device-hosted volumes are not created. Do not reject existing malformed headers at mount time, so users can still mount old OpenBSD-created volumes for recovery.
Refs #1589.
Refs #1593.
Allow normal file-hosted containers to use quick format in the Unix volume creation path by sizing the host file with ftruncate before backup headers are written.
Enable the GUI checkbox for normal file containers and honor --quick in text mode. Update the Unix HTML documentation for the weaker deniability properties of sparse or unwritten host regions.
Argon2id includes the requested output length in its computation, so deriving 192 bytes and using a prefix is not equivalent to deriving only the selected cipher's key material length. This differs from PBKDF2, where the prefix property made this detail invisible.
VeraCrypt derives the maximum header key material currently needed by the supported cipher/cascade set, which is 192 bytes, and then uses the required prefix for the selected encryption algorithm. For AES-XTS this means the first 64 bytes of the 192-byte Argon2id output are used.
Make this design rule explicit in code and documentation by introducing ARGON2_HEADER_KEYDATA_SIZE instead of relying implicitly on GetMaxPkcs5OutSize. If a future cipher or cascade requires more than 192 bytes, that must be handled as an explicit format/design change.
Document the 192-byte Argon2id header KDF output requirement so third-party implementations derive the same header key material.
References: https://github.com/veracrypt/VeraCrypt/issues/1614
Keep the NTFS kernel-driver option as a generic in-kernel NTFS path rather than an ntfs3-specific path. Add --filesystem=kernel-ntfs and -m kernelntfs routes that select a registered or loadable kernel NTFS driver and mount with -i so mount.ntfs/ntfs-3g helpers are not invoked.
Preserve --filesystem=ntfs3 as a literal pin to the ntfs3 driver. Treat both ntfs3 and kernel-ntfs as mount-only selectors; volume creation continues to use filesystem type NTFS.
The preference and -m kernelntfs path only select an in-kernel NTFS driver when no explicit filesystem type was supplied and blkid detects NTFS.
Treat ntfs as the preferred in-kernel driver on Linux 7.1 and later, where the upstream read/write driver is expected. On earlier kernels, select ntfs only when module metadata identifies the standalone read/write driver and /sys/module confirms it loaded, avoiding ntfs3 read-only ntfs compatibility registrations. Fall back to ntfs3 otherwise, and report a generic kernel-driver error if neither supported driver is available or loadable.
Rename the internal preference/config field to MountNtfsWithKernelDriver, migrate the old MountNtfsWithNtfs3 preference key, and update UI strings, CLI help, documentation, release notes, and translation placeholders accordingly.
Reference: https://github.com/veracrypt/VeraCrypt/issues/1735
Prefer hdiutil plist entities that carry a mount-point when recording the virtual device. This fixes APFS images where the first dev-entry is not the mounted volume.
Add a macOS mounted-volume refresh hook that recovers VirtualDevice and MountPoint from hdiutil info when FUSE-T SMB auxiliary metadata is missing or stale.
APFS volume creation can still fail with Permission denied after preparing the raw and block device aliases because newfs_apfs performs privileged APFS container and volume operations beyond opening the device nodes.
Route APFS formatting through the elevated CoreService path for non-root macOS runs. Keep the elevated interface narrow by sending only the target device and invoking user UID/GID, validate the device path on the privileged side, rebuild the formatter arguments there, and execute /sbin/newfs_apfs by absolute path to avoid PATH shadowing.
Pass -U/-G so the created filesystem preserves the invoking user ownership. Apply the same path to GUI and text-mode creation.
Report explicit progress stages while writing volume data, writing backup headers, and flushing data to disk so the wizard does not appear stuck at 100%.
Keep the wizard in progress during Unix post-creation formatting and show status for temporary mount/device setup, mkfs invocation, and dismount.
When normal filesystem unmount fails, the Linux path could stop before cleaning VeraCrypt mapper, loop and FUSE objects. Add an explicit emergency dismount request that is only reached after interactive confirmation.
The recovery path lazy-detaches mounted filesystems, uses deferred dmsetup removal for VeraCrypt mapper devices, detaches loop devices, and keeps normal force/ignoreOpenFiles behavior unchanged.
The read loop that captures stderr from the sudo child process used
`vector<char> buffer(4096); buffer.clear();` followed by
`read(fd, &buffer[0], buffer.capacity())`. This has two instances of
undefined behavior:
1. `operator[](0)` on a vector with `size() == 0` violates the C++
standard precondition `n < size()`. libstdc++ built with
`-D_GLIBCXX_ASSERTIONS` aborts the process with:
stl_vector.h:1128: Assertion '__n < this->size()' failed.
2. `buffer.begin() + bytesRead` on the same empty vector constructs
an iterator past `end()`, also UB.
`-D_GLIBCXX_ASSERTIONS` is in the default build flags of Arch Linux,
Fedora, and several other distributions. On those systems, the
unprivileged helper process aborts as soon as sudo writes anything
to stderr (a password prompt, a 'user is not in the sudoers file'
error, etc.). The main process then sees EOF on the service output
pipe, and throws `InsufficientData`, which renders to the user as
'Not enough data available'. A second mount attempt fails at
`File::Write` because the helper is dead and the pipe is broken,
producing the bare message 'VeraCrypt::File::Write:395'.
Fix by replacing `buffer` with a plain `char[4096]` and using
`reserve(4096)` on `errOutput` to preserve the original
pre-allocation intent. No behavioral change on systems where the UB
happened to work; aborts are eliminated on systems where the
assertions fire.
Reported-by: multiple users, see veracrypt/VeraCrypt#1550,
veracrypt/VeraCrypt#1446, veracrypt/VeraCrypt#844
Co-authored-by: rabbit <rabbit@github>
Make /aux-device-info readable for SMB, verify that FUSE records hdiutil device info after mount and recover missing virtual devices from hdiutil before dismounting auxiliary mounts.
Add statfs metadata for the auxiliary FUSE mount, keep /control read-only by sending hdiutil device data through /aux-device-info and tolerate delayed SMB rediscovery during mount completion. Log final control-file retry failures for diagnostics.
The cascade order has been updated so that SM4 is applied after the other cipher(s) (e.g., Serpent). This change reflects standard cryptanalytic guidance, which shows that the overall strength of a cascade is limited by the first encryption stage. Given that SM4 uses a 128-bit key, its post-quantum brute-force resistance is lower than ciphers with a 256-bit key (such as Serpent). By placing SM4 last, we ensure that any potential weakness in SM4 cannot reduce the security margin provided by the stronger cipher.
When VeraCrypt is run as an AppImage, the veracrypt binary resides in a SquashFS mount under /tmp which is inaccessible to root. Using this path with sudo results in a "command not found" error.
This patch detects the AppImage environment by checking both APPIMAGE and APPDIR variables, ensuring the executable path starts with APPDIR and that APPDIR starts with the expected "/tmp/.mount_Veracr" prefix. In this scenario, the AppImage file itself (APPIMAGE) is used as the executable for sudo, resolving the elevation issue.
Added security checks to prevent mounting VeraCrypt volumes on system directories (like /usr/bin) or directories in the user's PATH, which could theoretically allow execution of malicious binaries instead of legitimate system binaries.
Key changes:
- Block mounting on protected system directories (/usr, /bin, /lib, etc.)
This restriction cannot be overridden
- Block mounting on directories present in user's PATH environment variable
This can be overridden with --allow-insecure-mount flag
- Add visual warnings (red border, "[INSECURE MODE]") when mounting on PATH directories is allowed
- Handle symlinks properly when checking paths
- Add new error messages for blocked mount points
To override PATH-based restrictions only (system directories remain protected):
veracrypt --allow-insecure-mount [options] volume mountpoint
Security Impact: Low to Medium
The attack requires either:
- User explicitly choosing a system directory as mount point instead of using VeraCrypt's default mount points
- Or attacker having both filesystem access to modify favorites configuration AND knowledge of the volume password
Default mount points are not affected by this vulnerability.
Security: CVE-2025-23021
This commit fixes a critical security vulnerability where VeraCrypt could be tricked into executing malicious binaries with elevated privileges. The vulnerability has two severe implications:
1. When sudo's secure_path option is disabled, attackers could execute malicious binaries with root privileges by placing them in user-writable PATH directories (e.g., making "sudo mount" execute a malicious mount binary)
2. By placing a malicious sudo binary in PATH, attackers could intercept and steal the user's password when VeraCrypt prompts for sudo authentication
The vulnerability allowed attackers to place malicious binaries in user-writable directories that appear in PATH before system directories, potentially leading to privilege escalation and credential theft.
Key changes:
- Implement FindSystemBinary() to locate executables in secure system paths
- Replace all relative binary paths with absolute paths for system commands
- Add security checks for executable permissions
- Update process execution to use absolute paths for:
* sudo
* mount
* fsck
* terminal emulators
* file managers
* system utilities (hdiutil, mdconfig, vnconfig, lofiadm)
The fix ensures all system binaries are called using their absolute paths from secure system directories, preventing both privilege escalation through PATH manipulation and password theft through sudo hijacking.
Security: CVE-2024-54187
This update simplifies the logic for detecting active sudo sessions by checking the exit code of the sudo -n -l command, which reliably returns 0 if a session is active.
Additionally, this approach is now applicable to recent macOS versions, as they no longer have the sudo bug that previously prevented us from using this method.
If vulnerability detected, a warning message is displayed during mount or backup/restore header, and changing the password is disallowed since it will not change the master key.
The build script build_veracrypt_macosx.h now accepts the argument -f to enable fuse-t support.
It is also possible to set the environment variable VC_OSX_FUSET to 1 for FUSE-T support.
A change was done in CoreUnix::GetMountedVolumes to add a waiting loop for control file to be accessible because when using FUSE-T there always a delay before control file can be serialized.
The behaviour of `wc -l` is different on FreeBSD, in which the stdout
result is padded by spaces in the beginning, which causes that the
result[0] is not actually the value we care about. This patch adds
a translate removing all whitespace from the output.
* EMVCard.cpp: ArrayToHexWideString: prohibit conversion of a string constant
../Common/EMVCard.cpp: In function 'std::wstring VeraCrypt::ArrayToHexWideString(con
st unsigned char*, size_t)':
../Common/EMVCard.cpp:28:43: warning: ISO C++ forbids converting a string constant
to 'wchar_t*' [-Wwrite-strings]
28 | static wchar_t* hexChar = L"0123456789ABCDEF";
| ^~~~~~~~~~~~~~~~~~~
Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
* EMVCard.cpp: ArrayToHexWideString: fix of the comparison of different types
../Common/EMVCard.cpp: In function 'std::wstring VeraCrypt::ArrayToHexWideString(con
st unsigned char*, size_t)':
../Common/EMVCard.cpp:32:43: warning: comparison of integer expressions of different
signedness: 'int' and 'size_t' {aka 'long unsigned int'} [-Wsign-compare]
32 | for (int i = 0; i < cbData; i++)
| ~~^~~~~~~~
Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
* SecurityTokenKeyfilesDialog.cpp: removed initialization of an unused variable
Forms/SecurityTokenKeyfilesDialog.cpp:58:24: warning: unused variable 'i' [-Wunused-
variable]
58 | size_t i = 0;
| ^
Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
* Core/Unix: throwing an exception instead of ignoring the error
Fixes: 5a6b445f ("fix warnings and UB (#1164)")
Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
---------
Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
Co-authored-by: Vasiliy Kovalev <kovalev@altlinux.org>