1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2026-06-19 02:56:07 -05:00

Linux: refine in-kernel NTFS driver selection

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
This commit is contained in:
Mounir IDRASSI
2026-05-17 18:33:36 +09:00
parent 9535e65bd8
commit 6bef9e009c
66 changed files with 447 additions and 147 deletions
+1
View File
@@ -49,6 +49,7 @@ namespace VeraCrypt
TC_EXCEPTION (EncryptedSystemRequired); \
TC_EXCEPTION (HigherFuseVersionRequired); \
TC_EXCEPTION (KernelCryptoServiceTestFailed); \
TC_EXCEPTION (KernelNtfsDriverUnavailable); \
TC_EXCEPTION (LoopDeviceSetupFailed); \
TC_EXCEPTION (MountPointRequired); \
TC_EXCEPTION (MountPointUnavailable); \
+3 -3
View File
@@ -25,7 +25,7 @@ namespace VeraCrypt
TC_CLONE (FilesystemOptions);
TC_CLONE (FilesystemType);
#ifdef TC_LINUX
TC_CLONE (MountNtfsWithNtfs3);
TC_CLONE (MountNtfsWithKernelDriver);
#endif
TC_CLONE_SHARED (KeyfileList, Keyfiles);
TC_CLONE_SHARED (DirectoryPath, MountPoint);
@@ -66,7 +66,7 @@ namespace VeraCrypt
sr.Deserialize ("FilesystemOptions", FilesystemOptions);
sr.Deserialize ("FilesystemType", FilesystemType);
#ifdef TC_LINUX
sr.Deserialize ("MountNtfsWithNtfs3", MountNtfsWithNtfs3);
sr.Deserialize ("MountNtfsWithKernelDriver", MountNtfsWithKernelDriver);
#endif
Keyfiles = Keyfile::DeserializeList (stream, "Keyfiles");
@@ -139,7 +139,7 @@ namespace VeraCrypt
sr.Serialize ("FilesystemOptions", FilesystemOptions);
sr.Serialize ("FilesystemType", FilesystemType);
#ifdef TC_LINUX
sr.Serialize ("MountNtfsWithNtfs3", MountNtfsWithNtfs3);
sr.Serialize ("MountNtfsWithKernelDriver", MountNtfsWithKernelDriver);
#endif
Keyfile::SerializeList (stream, "Keyfiles", Keyfiles);
+2 -2
View File
@@ -27,7 +27,7 @@ namespace VeraCrypt
:
CachePassword (false),
#ifdef TC_LINUX
MountNtfsWithNtfs3 (false),
MountNtfsWithKernelDriver (false),
#endif
NoFilesystem (false),
NoHardwareCrypto (false),
@@ -55,7 +55,7 @@ namespace VeraCrypt
wstring FilesystemOptions;
wstring FilesystemType;
#ifdef TC_LINUX
bool MountNtfsWithNtfs3;
bool MountNtfsWithKernelDriver;
#endif
shared_ptr <KeyfileList> Keyfiles;
shared_ptr <DirectoryPath> MountPoint;
+195 -7
View File
@@ -18,6 +18,9 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#ifdef TC_LINUX
#include <sys/utsname.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include "Platform/FileStream.h"
@@ -30,6 +33,10 @@ namespace VeraCrypt
{
#ifdef TC_LINUX
static string GetTmpUser ();
static bool GetLinuxKernelVersion (int &kernelMajor, int &kernelMinor);
static bool IsLinuxKernelModuleLoaded (const string &moduleName);
static bool IsLinuxKernelVersionAtLeast (int major, int minor);
static bool IsNtfsReadWriteKernelModuleAvailable ();
static bool SamePath (const string& path1, const string& path2);
#endif
@@ -747,6 +754,82 @@ namespace VeraCrypt
}
#ifdef TC_LINUX
static bool GetLinuxKernelVersion (int &kernelMajor, int &kernelMinor)
{
struct utsname kernelInfo;
if (uname (&kernelInfo) != 0)
return false;
kernelMajor = 0;
kernelMinor = 0;
int versionFields = sscanf (kernelInfo.release, "%d.%d", &kernelMajor, &kernelMinor);
if (versionFields < 1)
return false;
return true;
}
static bool IsLinuxKernelVersionAtLeast (int major, int minor)
{
int kernelMajor = 0;
int kernelMinor = 0;
if (!GetLinuxKernelVersion (kernelMajor, kernelMinor))
return false;
return kernelMajor > major || (kernelMajor == major && kernelMinor >= minor);
}
static bool IsLinuxKernelModuleLoaded (const string &moduleName)
{
string modulePath = "/sys/module/" + moduleName;
struct stat moduleStat;
return stat (modulePath.c_str(), &moduleStat) == 0 && S_ISDIR (moduleStat.st_mode);
}
static bool IsNtfsReadWriteKernelModuleAvailable ()
{
list <string> args;
args.push_back ("-F");
args.push_back ("description");
args.push_back ("ntfs");
try
{
string description = StringConverter::ToLower (StringConverter::Trim (Process::Execute ("modinfo", args, 2000)));
// The upstream fs/ntfs module reports "NTFS read-write filesystem driver".
// ntfs3 compatibility aliases report different wording, such as read/write.
return description.find ("ntfs") != string::npos
&& description.find ("read-write") != string::npos
&& description.find ("filesystem driver") != string::npos;
}
catch (...) { }
return false;
}
bool CoreUnix::IsNtfsReadWriteKernelFilesystemTypeAvailable () const
{
if (!IsNtfsReadWriteKernelModuleAvailable ())
return false;
if (!IsLinuxKernelModuleLoaded ("ntfs"))
{
list <string> args;
args.push_back ("-q");
args.push_back ("-b");
args.push_back ("ntfs");
try
{
Process::Execute ("modprobe", args, 5000);
}
catch (...) { }
}
return IsLinuxKernelModuleLoaded ("ntfs") && IsFilesystemTypeRegistered ("ntfs");
}
string CoreUnix::DetectFilesystemType (const DevicePath &devicePath) const
{
list <string> args;
@@ -767,9 +850,113 @@ namespace VeraCrypt
return string();
}
}
bool CoreUnix::IsFilesystemTypeRegistered (const string &filesystemType) const
{
FILE *procFilesystems = fopen ("/proc/filesystems", "r");
if (!procFilesystems)
return false;
bool registered = false;
char line[256];
finally_do_arg (FILE *, procFilesystems, fclose (finally_arg););
while (fgets (line, sizeof (line), procFilesystems))
{
string entry = StringConverter::Trim (line);
size_t separator = entry.find_last_of (" \t");
if (separator != string::npos)
entry = entry.substr (separator + 1);
if (entry == filesystemType)
{
registered = true;
break;
}
}
return registered;
}
bool CoreUnix::IsKernelFilesystemTypeAvailable (const string &filesystemType) const
{
if (IsFilesystemTypeRegistered (filesystemType))
return true;
// This is only used from mount-time paths that run with root-equivalent privileges.
// If a future unprivileged caller uses it, modprobe is expected to fail silently here.
list <string> moduleNames;
moduleNames.push_back (filesystemType);
moduleNames.push_back ("fs-" + filesystemType);
foreach (const string &moduleName, moduleNames)
{
list <string> args;
args.push_back ("-q");
args.push_back ("-b");
args.push_back (moduleName);
try
{
Process::Execute ("modprobe", args, 5000);
}
catch (...) { }
if (IsFilesystemTypeRegistered (filesystemType))
return true;
}
return false;
}
string CoreUnix::SelectNtfsKernelFilesystemType () const
{
bool kernelHasStandaloneNtfs = IsLinuxKernelVersionAtLeast (7, 1);
// Linux 6.9-7.0 may expose an "ntfs" compatibility alias from ntfs3,
// but that legacy mount path is forced read-only. Only use "ntfs" where
// the standalone read/write in-kernel driver is expected upstream, or when
// module metadata and /sys/module positively identify a loaded backport as
// the modern driver. Do not trust a pre-existing "ntfs" registration on
// pre-7.1 kernels; it may belong to ntfs3's read-only compatibility path.
if (!kernelHasStandaloneNtfs && IsNtfsReadWriteKernelFilesystemTypeAvailable ())
return "ntfs";
if (kernelHasStandaloneNtfs && IsKernelFilesystemTypeAvailable ("ntfs"))
return "ntfs";
if (IsKernelFilesystemTypeAvailable ("ntfs3"))
return "ntfs3";
throw KernelNtfsDriverUnavailable (SRC_POS);
}
void CoreUnix::ResolveNtfsKernelMountOptions (const DevicePath &devicePath, bool mountNtfsWithKernelDriver,
wstring &filesystemType, bool &internalMountOnly) const
{
string requestedFilesystemType = StringConverter::ToLower (StringConverter::ToSingle (filesystemType));
bool explicitKernelNtfsRequest = requestedFilesystemType == "kernel-ntfs" || requestedFilesystemType == "ntfs-kernel";
if (requestedFilesystemType == "ntfs3")
{
// mount.ntfs3 helpers are not required; -i keeps mount(8) on the kernel path.
internalMountOnly = true;
return;
}
if (!explicitKernelNtfsRequest
&& !(mountNtfsWithKernelDriver
&& filesystemType.empty()
&& DetectFilesystemType (devicePath) == "ntfs"))
return;
filesystemType = StringConverter::ToWide (SelectNtfsKernelFilesystemType());
internalMountOnly = true;
}
#endif
void CoreUnix::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
void CoreUnix::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly) const
{
if (GetMountedFilesystems (DevicePath(), mountPoint).size() > 0)
throw MountPointUnavailable (SRC_POS);
@@ -777,6 +964,9 @@ namespace VeraCrypt
list <string> args;
string options;
if (internalMountOnly)
args.push_back ("-i");
if (!filesystemType.empty())
{
#ifdef TC_SOLARIS
@@ -1118,19 +1308,17 @@ namespace VeraCrypt
if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty())
{
wstring filesystemType = options.FilesystemType;
bool internalMountOnly = false;
#ifdef TC_LINUX
if (options.MountNtfsWithNtfs3 && filesystemType.empty()
&& DetectFilesystemType (loopDev) == "ntfs")
{
filesystemType = L"ntfs3";
}
ResolveNtfsKernelMountOptions (loopDev, options.MountNtfsWithKernelDriver, filesystemType, internalMountOnly);
#endif
MountFilesystem (loopDev, *options.MountPoint,
StringConverter::ToSingle (filesystemType),
options.Protection == VolumeProtection::ReadOnly,
StringConverter::ToSingle (options.FilesystemOptions));
StringConverter::ToSingle (options.FilesystemOptions),
internalMountOnly);
}
return loopDev;
+8 -1
View File
@@ -70,12 +70,19 @@ namespace VeraCrypt
virtual uid_t GetRealUserId () const;
virtual gid_t GetRealGroupId () const;
virtual string GetTempDirectory () const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
// internalMountOnly maps to mount(8) -i and suppresses /sbin/mount.<type> helpers.
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly = false) const;
virtual DevicePath MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const;
virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const { throw NotApplicable (SRC_POS); }
virtual void UpdateMountedVolumeInfo (shared_ptr <VolumeInfo> mountedVolume) const { (void) mountedVolume; }
#ifdef TC_LINUX
string DetectFilesystemType (const DevicePath &devicePath) const;
bool IsFilesystemTypeRegistered (const string &filesystemType) const;
bool IsKernelFilesystemTypeAvailable (const string &filesystemType) const;
bool IsNtfsReadWriteKernelFilesystemTypeAvailable () const;
void ResolveNtfsKernelMountOptions (const DevicePath &devicePath, bool mountNtfsWithKernelDriver,
wstring &filesystemType, bool &internalMountOnly) const;
string SelectNtfsKernelFilesystemType () const;
#endif
private:
+3 -1
View File
@@ -183,8 +183,10 @@ namespace VeraCrypt
return mountedFilesystems;
}
void CoreFreeBSD::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
void CoreFreeBSD::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly) const
{
(void) internalMountOnly;
std::string chosenFilesystem = "msdos";
std::string modifiedMountOptions = systemMountOptions;
+1 -1
View File
@@ -30,7 +30,7 @@ namespace VeraCrypt
virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const;
virtual void DetachLoopDevice (const DevicePath &devicePath) const;
virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly = false) const;
private:
CoreFreeBSD (const CoreFreeBSD &);
+7 -9
View File
@@ -455,7 +455,7 @@ namespace VeraCrypt
return mountedFilesystems;
}
void CoreLinux::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
void CoreLinux::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly) const
{
bool fsMounted = false;
@@ -466,14 +466,14 @@ namespace VeraCrypt
stringstream userMountOptions;
userMountOptions << "uid=" << GetRealUserId() << ",gid=" << GetRealGroupId() << ",umask=077" << (!systemMountOptions.empty() ? "," : "");
CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, userMountOptions.str() + systemMountOptions);
CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, userMountOptions.str() + systemMountOptions, internalMountOnly);
fsMounted = true;
}
}
catch (...) { }
if (!fsMounted)
CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, systemMountOptions);
CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, systemMountOptions, internalMountOnly);
}
void CoreLinux::MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const
@@ -629,17 +629,15 @@ namespace VeraCrypt
if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty())
{
wstring filesystemType = options.FilesystemType;
bool internalMountOnly = false;
if (options.MountNtfsWithNtfs3 && filesystemType.empty()
&& DetectFilesystemType (nativeDevPath) == "ntfs")
{
filesystemType = L"ntfs3";
}
ResolveNtfsKernelMountOptions (nativeDevPath, options.MountNtfsWithKernelDriver, filesystemType, internalMountOnly);
MountFilesystem (nativeDevPath, *options.MountPoint,
StringConverter::ToSingle (filesystemType),
options.Protection == VolumeProtection::ReadOnly,
StringConverter::ToSingle (options.FilesystemOptions));
StringConverter::ToSingle (options.FilesystemOptions),
internalMountOnly);
filesystemMounted = true;
}
+1 -1
View File
@@ -33,7 +33,7 @@ namespace VeraCrypt
virtual void DismountNativeVolumeDeferred (shared_ptr <VolumeInfo> mountedVolume) const;
virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const;
virtual bool IsLoopDeviceAttached (const DevicePath &devicePath) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly = false) const;
virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const;
private:
+3 -1
View File
@@ -141,8 +141,10 @@ namespace VeraCrypt
return mountedFilesystems;
}
void CoreOpenBSD::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
void CoreOpenBSD::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly) const
{
(void) internalMountOnly;
try
{
// Try to mount FAT by default as mount is unable to probe filesystem type on BSD
+1 -1
View File
@@ -33,7 +33,7 @@ namespace VeraCrypt
virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const;
virtual void DetachLoopDevice (const DevicePath &devicePath) const;
virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly = false) const;
private:
CoreOpenBSD (const CoreOpenBSD &);
+3 -1
View File
@@ -157,8 +157,10 @@ namespace VeraCrypt
return mountedFilesystems;
}
void CoreSolaris::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
void CoreSolaris::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly) const
{
(void) internalMountOnly;
try
{
// Try to mount FAT by default as mount is unable to probe filesystem type on Solaris
+1 -1
View File
@@ -30,7 +30,7 @@ namespace VeraCrypt
virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const;
virtual void DetachLoopDevice (const DevicePath &devicePath) const;
virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions, bool internalMountOnly = false) const;
private:
CoreSolaris (const CoreSolaris &);