OpenBSD: add FFS volume formatting support

Expose FFS as the native OpenBSD filesystem option for volume creation and accept FFS/UFS on the command line, mapping mounts to the OpenBSD ffs filesystem type.

Run newfs through the elevated core service on vnd raw devices, then temporarily mount the new filesystem to transfer root directory ownership back to the invoking user.

Keep the non-interactive creation default as FAT on OpenBSD so existing unattended scripts do not start requiring elevation.
This commit is contained in:
Mounir IDRASSI committed 2026-07-06 17:11:24 +09:00
1 parent ede12bf81c
commit 48f8d87418
13 files changed
+471 -25

No files matched your search

+6
View File
@@ -415,6 +415,12 @@ namespace VeraCrypt
ArgFilesystem = VolumeCreationOptions::FilesystemType::NTFS;
else if (str.IsSameAs (L"exFAT", false))
ArgFilesystem = VolumeCreationOptions::FilesystemType::exFAT;
#elif defined (TC_OPENBSD)
else if (str.IsSameAs (L"FFS", false) || str.IsSameAs (L"UFS", false))
{
ArgMountOptions.FilesystemType = L"ffs";
ArgFilesystem = VolumeCreationOptions::FilesystemType::FFS;
}
#endif
else
throw_err (LangString["UNKNOWN_OPTION"] + L": " + str);
+31 -12
View File
@@ -25,6 +25,9 @@
#ifdef TC_MACOSX
#include "Main/MacOSXFormatterDevice.h"
#endif
#ifdef TC_OPENBSD
#include "Main/OpenBSDFormatterDevice.h"
#endif
#include "Main/Resources.h"
#include "VolumeCreationWizard.h"
#include "EncryptionOptionsWizardPage.h"
@@ -857,9 +860,11 @@ namespace VeraCrypt
// Temporarily take ownership of the device if the user is not an administrator
DevicePath virtualDevice = volume->VirtualDevice;
DevicePath formatterDevice = virtualDevice;
#ifdef TC_MACOSX
string virtualDeviceStr = virtualDevice;
virtualDevice = GetMacOSXRawDevicePath (virtualDeviceStr);
formatterDevice = virtualDevice;
MacOSXFormatterDeviceOwnerRestoreList changedDeviceOwners;
finally_do_arg (MacOSXFormatterDeviceOwnerRestoreList *, &changedDeviceOwners,
@@ -868,25 +873,37 @@ namespace VeraCrypt
});
bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter);
if (!useElevatedAPFSFormatter)
PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners);
PrepareMacOSXFormatterDevice (formatterDevice, changedDeviceOwners);
#else
#ifdef TC_OPENBSD
if (SelectedFilesystemType == VolumeCreationOptions::FilesystemType::FFS)
formatterDevice = GetOpenBSDRawFormatterDevicePath (virtualDevice);
#endif
bool prepareFormatterDeviceOwnership = true;
#ifdef TC_OPENBSD
if (SelectedFilesystemType == VolumeCreationOptions::FilesystemType::FFS)
prepareFormatterDeviceOwnership = false;
#endif
UserId origDeviceOwner ((uid_t) -1);
try
if (prepareFormatterDeviceOwnership)
{
File file;
file.Open (virtualDevice, File::OpenReadWrite);
}
catch (...)
{
if (!Core->HasAdminPrivileges())
try
{
origDeviceOwner = virtualDevice.GetOwner();
Core->SetFileOwner (virtualDevice, UserId (getuid()));
File file;
file.Open (formatterDevice, File::OpenReadWrite);
}
catch (...)
{
if (!Core->HasAdminPrivileges())
{
origDeviceOwner = formatterDevice.GetOwner();
Core->SetFileOwner (formatterDevice, UserId (getuid()));
}
}
}
finally_do_arg2 (FilesystemPath, virtualDevice, UserId, origDeviceOwner,
finally_do_arg2 (FilesystemPath, formatterDevice, UserId, origDeviceOwner,
{
if (finally_arg2.SystemId != (uid_t) -1)
Core->SetFileOwner (finally_arg, finally_arg2);
@@ -921,11 +938,13 @@ namespace VeraCrypt
AddMacOSXAPFSFormatterUserArgs (args);
#endif
args.push_back (string (virtualDevice));
args.push_back (string (formatterDevice));
SetCreationProgressText (StringFormatter (LangString["FORMAT_STAGE_CREATING_FILESYSTEM"], fsFormatter));
#ifdef TC_MACOSX
ExecuteMacOSXFilesystemFormatter (fsFormatter, args);
#elif defined (TC_OPENBSD)
ExecuteOpenBSDFilesystemFormatter (fsFormatter, args);
#else
Process::Execute (fsFormatter, args);
#endif
@@ -52,6 +52,8 @@ namespace VeraCrypt
FilesystemTypeChoice->Append (L"APFS", (void *) VolumeCreationOptions::FilesystemType::APFS);
#elif defined (TC_FREEBSD) || defined (TC_SOLARIS)
FilesystemTypeChoice->Append (L"UFS", (void *) VolumeCreationOptions::FilesystemType::UFS);
#elif defined (TC_OPENBSD)
FilesystemTypeChoice->Append (L"FFS", (void *) VolumeCreationOptions::FilesystemType::FFS);
#endif
if (!disable32bitFilesystems && filesystemSize <= TC_MAX_FAT_SECTOR_COUNT * sectorSize)
@@ -94,6 +96,7 @@ namespace VeraCrypt
case VolumeCreationOptions::FilesystemType::MacOsExt: FilesystemTypeChoice->SetStringSelection (L"Mac OS Extended"); break;
case VolumeCreationOptions::FilesystemType::APFS: FilesystemTypeChoice->SetStringSelection (L"APFS"); break;
case VolumeCreationOptions::FilesystemType::UFS: FilesystemTypeChoice->SetStringSelection (L"UFS"); break;
case VolumeCreationOptions::FilesystemType::FFS: FilesystemTypeChoice->SetStringSelection (L"FFS"); break;
default:
throw ParameterIncorrect (SRC_POS);
+123
View File
@@ -0,0 +1,123 @@
/*
VeraCrypt source code
Copyright (c) 2026 AM Crypto
This file is part of VeraCrypt and is governed by the Apache License 2.0
the full text of which is contained in the file License.txt included in
VeraCrypt binary and source code distribution packages.
*/
#ifndef TC_HEADER_Main_OpenBSDFormatterDevice
#define TC_HEADER_Main_OpenBSDFormatterDevice
#include "Main/Main.h"
#ifdef TC_OPENBSD
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "Core/Unix/CoreService.h"
#include "Core/Unix/UnixUser.h"
#include "Platform/Unix/Process.h"
namespace VeraCrypt
{
inline bool IsOpenBSDVndDevicePath (const string &path, bool rawDevice)
{
const string prefix = rawDevice ? "/dev/rvnd" : "/dev/vnd";
if (path.find (prefix) != 0)
return false;
size_t numberStart = prefix.size();
size_t numberEnd = numberStart;
while (numberEnd < path.size() && path[numberEnd] >= '0' && path[numberEnd] <= '9')
++numberEnd;
return numberEnd > numberStart
&& numberEnd + 1 == path.size()
&& path[numberEnd] == 'c';
}
inline DevicePath GetOpenBSDRawFormatterDevicePath (const DevicePath &path)
{
string pathStr = path;
if (IsOpenBSDVndDevicePath (pathStr, true))
return path;
if (IsOpenBSDVndDevicePath (pathStr, false))
return DevicePath (string ("/dev/r") + pathStr.substr (5));
return path;
}
inline string GetOpenBSDFormatterName (const string &fsFormatter)
{
size_t namePos = fsFormatter.find_last_of ('/');
return namePos == string::npos ? fsFormatter : fsFormatter.substr (namePos + 1);
}
inline bool IsOpenBSDFFSFormatter (const string &fsFormatter)
{
return GetOpenBSDFormatterName (fsFormatter) == "newfs";
}
inline bool GetOpenBSDFormatterEnvId (const char *name, uint64 &id)
{
const char *env = getenv (name);
if (!env || !env[0])
return false;
char *endPtr = nullptr;
errno = 0;
unsigned long long value = strtoull (env, &endPtr, 10);
if (errno != 0 || !endPtr || *endPtr != '\0')
return false;
id = static_cast <uint64> (value);
return true;
}
inline uint64 GetOpenBSDFormatterOwnerUserId ()
{
uint64 id;
if (GetOpenBSDFormatterEnvId ("SUDO_UID", id))
return id;
uid_t doasUid;
if (GetDoasUserIds (&doasUid, nullptr))
return static_cast <uint64> (doasUid);
return static_cast <uint64> (getuid());
}
inline uint64 GetOpenBSDFormatterOwnerGroupId ()
{
uint64 id;
if (GetOpenBSDFormatterEnvId ("SUDO_GID", id))
return id;
gid_t doasGid;
if (GetDoasUserIds (nullptr, &doasGid))
return static_cast <uint64> (doasGid);
return static_cast <uint64> (getgid());
}
inline void ExecuteOpenBSDFilesystemFormatter (const string &fsFormatter, const list <string> &args)
{
if (IsOpenBSDFFSFormatter (fsFormatter))
{
if (args.empty())
throw ParameterIncorrect (SRC_POS);
CoreService::RequestExecuteOpenBSDFFSFormatter (DevicePath (args.back()), GetOpenBSDFormatterOwnerUserId(), GetOpenBSDFormatterOwnerGroupId());
return;
}
Process::Execute (fsFormatter, args);
}
}
#endif // TC_OPENBSD
#endif // TC_HEADER_Main_OpenBSDFormatterDevice
+39 -12
View File
@@ -29,6 +29,9 @@
#ifdef TC_MACOSX
#include "Main/MacOSXFormatterDevice.h"
#endif
#ifdef TC_OPENBSD
#include "Main/OpenBSDFormatterDevice.h"
#endif
#include "TextUserInterface.h"
namespace VeraCrypt
@@ -933,7 +936,13 @@ namespace VeraCrypt
{
if (Preferences.NonInteractive)
{
#ifdef TC_OPENBSD
// Preserve the historical OpenBSD batch default. Native FFS
// formatting requires elevation, so scripts should opt in.
options->Filesystem = VolumeCreationOptions::FilesystemType::FAT;
#else
options->Filesystem = VolumeCreationOptions::FilesystemType::GetPlatformNative();
#endif
}
else
{
@@ -974,6 +983,8 @@ namespace VeraCrypt
}
#elif defined (TC_FREEBSD) || defined (TC_SOLARIS)
ShowInfo (wxString::Format (L" %li) %s", filesystems.size() + 1, "UFS")); filesystems.push_back (VolumeCreationOptions::FilesystemType::UFS);
#elif defined (TC_OPENBSD)
ShowInfo (wxString::Format (L" %li) %s", filesystems.size() + 1, "FFS")); filesystems.push_back (VolumeCreationOptions::FilesystemType::FFS);
#endif
ssize_t defaultFilesystem = fatAvailable ? 2 : 1;
@@ -1123,9 +1134,11 @@ namespace VeraCrypt
// Temporarily take ownership of the device if the user is not an administrator
DevicePath virtualDevice = volume->VirtualDevice;
DevicePath formatterDevice = virtualDevice;
#ifdef TC_MACOSX
string virtualDeviceStr = virtualDevice;
virtualDevice = GetMacOSXRawDevicePath (virtualDeviceStr);
formatterDevice = virtualDevice;
MacOSXFormatterDeviceOwnerRestoreList changedDeviceOwners;
finally_do_arg (MacOSXFormatterDeviceOwnerRestoreList *, &changedDeviceOwners,
@@ -1134,25 +1147,37 @@ namespace VeraCrypt
});
bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter);
if (!useElevatedAPFSFormatter)
PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners);
PrepareMacOSXFormatterDevice (formatterDevice, changedDeviceOwners);
#else
#ifdef TC_OPENBSD
if (options->Filesystem == VolumeCreationOptions::FilesystemType::FFS)
formatterDevice = GetOpenBSDRawFormatterDevicePath (virtualDevice);
#endif
bool prepareFormatterDeviceOwnership = true;
#ifdef TC_OPENBSD
if (options->Filesystem == VolumeCreationOptions::FilesystemType::FFS)
prepareFormatterDeviceOwnership = false;
#endif
UserId origDeviceOwner ((uid_t) -1);
try
if (prepareFormatterDeviceOwnership)
{
File file;
file.Open (virtualDevice, File::OpenReadWrite);
}
catch (...)
{
if (!Core->HasAdminPrivileges())
try
{
origDeviceOwner = virtualDevice.GetOwner();
Core->SetFileOwner (virtualDevice, UserId (getuid()));
File file;
file.Open (formatterDevice, File::OpenReadWrite);
}
catch (...)
{
if (!Core->HasAdminPrivileges())
{
origDeviceOwner = formatterDevice.GetOwner();
Core->SetFileOwner (formatterDevice, UserId (getuid()));
}
}
}
finally_do_arg2 (FilesystemPath, virtualDevice, UserId, origDeviceOwner,
finally_do_arg2 (FilesystemPath, formatterDevice, UserId, origDeviceOwner,
{
if (finally_arg2.SystemId != (uid_t) -1)
Core->SetFileOwner (finally_arg, finally_arg2);
@@ -1187,10 +1212,12 @@ namespace VeraCrypt
AddMacOSXAPFSFormatterUserArgs (args);
#endif
args.push_back (string (virtualDevice));
args.push_back (string (formatterDevice));
#ifdef TC_MACOSX
ExecuteMacOSXFilesystemFormatter (fsFormatter, args);
#elif defined (TC_OPENBSD)
ExecuteOpenBSDFilesystemFormatter (fsFormatter, args);
#else
Process::Execute (fsFormatter, args);
#endif
+4
View File
@@ -1373,6 +1373,10 @@ const FileManager fileManagers[] = {
" with option -t. Default type is 'auto'. When creating a new volume, this\n"
" option specifies the filesystem to be created on the new volume.\n"
" Filesystem type 'none' disables mounting or creating a filesystem.\n"
#ifdef TC_OPENBSD
" On OpenBSD, filesystem type 'FFS' creates a native FFS volume and\n"
" mounts with filesystem type 'ffs'.\n"
#endif
#ifdef TC_LINUX
" On Linux, filesystem type 'ntfs3' mounts with the in-kernel ntfs3\n"
" driver and bypasses mount helpers. Filesystem type 'kernel-ntfs'\n"