From: David Uhden Collado Subject: [UPDATE] security/veracrypt 1.25.9 -> 1.26.29 + improvements To: ports@openbsd.org Date: Wed, 14 Oct 2026 19:51:00 +0000 Hello, Please find attached a patch updating security/veracrypt from 1.25.9 to 1.26.29, including native OpenBSD privilege elevation and FFS support. Upstream source: https://launchpad.net/veracrypt/trunk/1.26.29/+download/ The main OpenBSD-specific changes are: - Replace sudo with doas for the privileged core service. - Support restricted doas.conf rules allowing only --core-service. - Handle password authentication through a private pseudoterminal, without exposing credentials through argv or the environment. - Add native FFS creation using /sbin/newfs through a restricted privileged service request. - Preserve FAT as the default for noninteractive volume creation. - Remove the obsolete coreutils dependency and add pcsc-lite. - Fix reproducible-build date handling with OpenBSD's awk. - Update distinfo, PLIST, patches, documentation and the desktop icon. - Enable the upstream cryptographic self-tests through make test. The doas implementation supports password authentication and retries after incorrect credentials. The FFS formatter validates the target vnd device before requesting the privileged operation. I built, packaged, installed and tested VeraCrypt 1.26.29 on OpenBSD 8.0-current amd64. The cryptographic self-tests passed, including when executed by an unprivileged user. I also verified restricted doas permissions, password authentication, FFS volume creation, mounting, writing, reading, unmounting and remounting. File integrity was confirmed using SHA256, and fsck_ffs reported no errors. The existing FAT creation and mounting behavior was also tested successfully. These tests uncovered and helped resolve several privilege-related problems that were not apparent when running as root. Testing was limited to the CLI and regular file-backed volumes on amd64. The GUI builds but has not been tested interactively. Other architectures, physical devices, hidden volumes and smartcards remain untested. I would particularly appreciate review of the privilege elevation changes and additional testing on other architectures. Thank you for your time and consideration. Best regards, David. Index: security/veracrypt/Makefile =================================================================== RCS file: /cvs/ports/security/veracrypt/Makefile,v diff -u -p -u -r1.8 Makefile --- security/veracrypt/Makefile 17 Dec 2024 05:49:59 -0000 1.8 +++ security/veracrypt/Makefile 14 Oct 2026 19:04:23 -0000 @@ -2,23 +2,22 @@ BROKEN-sparc64= relocation truncated to COMMENT= free open source disk encryption software -V= 1.25.9 +V= 1.26.29 DISTNAME= VeraCrypt_${V}_Source PKGNAME= veracrypt-${V} CATEGORIES= security HOMEPAGE= https://www.veracrypt.fr/ -REVISION= 1 MAINTAINER= Tietoturvamies # Apache2 -PERMIT_PACKAGE= yes +PERMIT_PACKAGE= Yes SITES= https://launchpad.net/veracrypt/trunk/${V}/+download/ EXTRACT_SUFX= .tar.bz2 FIX_EXTRACT_PERMISSIONS=Yes -# C++11 +# C++14 COMPILER= base-clang ports-gcc CXXFLAGS_base-clang = -std=c++14 @@ -26,16 +25,16 @@ CXXFLAGS_base-clang = -std=c++14 WANTLIB += ${COMPILER_LIBCXX} c m fuse wx_baseu-3.2 wx_gtk3u_core-3.2 BUILD_DEPENDS= devel/yasm \ - sysutils/coreutils + security/pcsc-lite LIB_DEPENDS= x11/wxWidgets RUN_DEPENDS= devel/desktop-file-utils \ - security/sudo + security/pcsc-lite WRKDIST= ${WRKDIR}/src USE_GMAKE= Yes -ALL_TARGET= +ALL_TARGET= MAKE_FLAGS= VERBOSE=1 \ NOTEST=1 \ CC="${CC}" \ @@ -43,7 +42,6 @@ MAKE_FLAGS= VERBOSE=1 \ PORT_CFLAGS="${CFLAGS}" \ PORT_CXXFLAGS="${CXXFLAGS}" -NO_TEST= Yes .if ${MACHINE_ARCH:Mi386} MAKE_ENV+= LFLAGS=-Wl,-z,notext @@ -52,13 +50,16 @@ MAKE_ENV+= LFLAGS=-Wl,-z,notext pre-configure: ${SUBST_CMD} ${WRKSRC}/Setup/FreeBSD/veracrypt.desktop +do-test: + ${WRKSRC}/Main/veracrypt --text --test + do-install: ${INSTALL_PROGRAM} ${WRKSRC}/Main/veracrypt ${PREFIX}/bin ${INSTALL_DATA_DIR} ${PREFIX}/share/applications ${INSTALL_DATA} ${WRKSRC}/Setup/FreeBSD/veracrypt.desktop \ ${PREFIX}/share/applications ${INSTALL_DATA_DIR} ${PREFIX}/share/pixmaps/ - ${INSTALL_DATA} ${WRKSRC}/Resources/Icons/VeraCrypt-48x48.xpm \ - ${PREFIX}/share/pixmaps/veracrypt.xpm + ${INSTALL_DATA} ${WRKSRC}/Resources/Icons/VeraCrypt-48x48.png \ + ${PREFIX}/share/pixmaps/veracrypt.png .include Index: security/veracrypt/distinfo =================================================================== RCS file: /cvs/ports/security/veracrypt/distinfo,v diff -u -p -u -r1.2 distinfo --- security/veracrypt/distinfo 14 Mar 2022 11:07:46 -0000 1.2 +++ security/veracrypt/distinfo 14 Oct 2026 19:04:23 -0000 @@ -1,2 +1,2 @@ -SHA256 (VeraCrypt_1.25.9_Source.tar.bz2) = drbhgYS8IaQdKUn/Y9ch1JBUpxbO/zpL13tcNRC3lK8= -SIZE (VeraCrypt_1.25.9_Source.tar.bz2) = 24438846 +SHA256 (VeraCrypt_1.26.29_Source.tar.bz2) = YIJnMeKYK0vSMeOTDoWkQ5EWljhnGhsgDFGPjItGyyo= +SIZE (VeraCrypt_1.26.29_Source.tar.bz2) = 36302144 Index: security/veracrypt/patches/patch-Makefile =================================================================== RCS file: /cvs/ports/security/veracrypt/patches/patch-Makefile,v diff -u -p -u -r1.3 patch-Makefile --- security/veracrypt/patches/patch-Makefile 14 Mar 2022 11:07:46 -0000 1.3 +++ security/veracrypt/patches/patch-Makefile 14 Oct 2026 19:04:23 -0000 @@ -4,16 +4,16 @@ Index: Makefile --- Makefile.orig +++ Makefile -@@ -47,7 +47,7 @@ export CFLAGS := -Wall +@@ -50,7 +50,7 @@ export CXXFLAGS := -Wall -Wno-unused-parameter - C_CXX_FLAGS := -MMD -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES -I$(BASE_DIR) -I$(BASE_DIR)/Crypto + C_CXX_FLAGS := -MMD -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES -I$(BASE_DIR) -I$(BASE_DIR)/Crypto -DARGON2_NO_THREADS -I$(BASE_DIR)/Crypto/Argon2/include export ASFLAGS := -D __GNUC__ -D __YASM__ -export LFLAGS := +export LFLAGS ?= + export PKG_CONFIG ?= pkg-config export PKG_CONFIG_PATH ?= /usr/local/lib/pkgconfig - -@@ -109,7 +109,7 @@ endif +@@ -111,7 +111,7 @@ ifeq "$(TC_BUILD_CONFIG)" "Release" @@ -22,7 +22,7 @@ Index: Makefile export WX_BUILD_DIR ?= $(BASE_DIR)/wxrelease WX_CONFIGURE_FLAGS += --disable-debug_flag --disable-debug_gdb --disable-debug_info -@@ -441,8 +441,8 @@ endif +@@ -585,8 +585,8 @@ #------ Common configuration ------ @@ -32,4 +32,4 @@ Index: Makefile +CXXFLAGS := $(C_CXX_FLAGS) $(CXXFLAGS) $(TC_EXTRA_CXXFLAGS) $(PORT_CXXFLAGS) LFLAGS := $(LFLAGS) $(TC_EXTRA_LFLAGS) - WX_CONFIGURE_FLAGS += --enable-unicode -disable-shared --disable-dependency-tracking --enable-exceptions --enable-std_string --enable-dataobj --enable-mimetype + #------ Reproducible build configuration ------ Index: security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop =================================================================== RCS file: /cvs/ports/security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop,v diff -u -p -u -r1.2 patch-Setup_FreeBSD_veracrypt_desktop --- security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop 11 Mar 2022 19:54:08 -0000 1.2 +++ security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop 14 Oct 2026 19:04:23 -0000 @@ -1,12 +1,15 @@ +Point the desktop launcher at the executable installed under TRUEPREFIX +rather than the upstream /usr/bin path. + Index: Setup/FreeBSD/veracrypt.desktop --- Setup/FreeBSD/veracrypt.desktop.orig +++ Setup/FreeBSD/veracrypt.desktop -@@ -3,7 +3,7 @@ Encoding=UTF-8 - Name=VeraCrypt - GenericName=VeraCrypt - Comment=VeraCrypt --Exec=/usr/bin/veracrypt -+Exec=${TRUEPREFIX}/bin/veracrypt +@@ -4,7 +4,7 @@ + GenericName=VeraCrypt volume manager + Comment=Create and mount VeraCrypt encrypted volumes Icon=veracrypt +-Exec=/usr/bin/veracrypt %f ++Exec=${TRUEPREFIX}/bin/veracrypt %f + Categories=Security;Utility;Filesystem + Keywords=encryption,filesystem Terminal=false - Type=Application Index: security/veracrypt/pkg/PLIST =================================================================== RCS file: /cvs/ports/security/veracrypt/pkg/PLIST,v diff -u -p -u -r1.2 PLIST --- security/veracrypt/pkg/PLIST 11 Mar 2022 19:54:08 -0000 1.2 +++ security/veracrypt/pkg/PLIST 14 Oct 2026 19:04:23 -0000 @@ -1,5 +1,6 @@ @bin bin/veracrypt share/applications/veracrypt.desktop +share/doc/pkg-readmes/${PKGSTEM} share/pixmaps/ -share/pixmaps/veracrypt.xpm +share/pixmaps/veracrypt.png @tag update-desktop-database Index: security/veracrypt/patches/patch-Build_Tools_source_date_epoch_sh =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Build_Tools_source_date_epoch_sh @@ -0,0 +1,20 @@ +Continue the month_number ternary expression explicitly: OpenBSD's awk +does not accept a bare newline after ':' as a line continuation, so the +release date could not be derived from Common/Tcdefs.h. + +Index: Build/Tools/source_date_epoch.sh +--- Build/Tools/source_date_epoch.sh.orig ++++ Build/Tools/source_date_epoch.sh +@@ -60,9 +60,9 @@ + RELEASE_EPOCH=$(awk ' + function leap(y) { return ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) } + function month_number(name) { +- return (name == "January" ? 1 : name == "February" ? 2 : name == "March" ? 3 : +- name == "April" ? 4 : name == "May" ? 5 : name == "June" ? 6 : +- name == "July" ? 7 : name == "August" ? 8 : name == "September" ? 9 : ++ return (name == "January" ? 1 : name == "February" ? 2 : name == "March" ? 3 : \ ++ name == "April" ? 4 : name == "May" ? 5 : name == "June" ? 6 : \ ++ name == "July" ? 7 : name == "August" ? 8 : name == "September" ? 9 : \ + name == "October" ? 10 : name == "November" ? 11 : name == "December" ? 12 : 0); + } + function mdays(m, y) { return (m == 2 ? 28 + leap(y) : (m == 4 || m == 6 || m == 9 || m == 11 ? 30 : 31)) } Index: security/veracrypt/patches/patch-Common_Tcdefs_h =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Common_Tcdefs_h @@ -0,0 +1,16 @@ +Set TC_STR_RELEASE_DATE to June 9, 2026, matching TC_RELEASE_DATE_DAY +and the upstream "Set release date to June 9th 2026" commit. The awk +helper in Build/Tools/source_date_epoch.sh requires both dates to agree. + +Index: Common/Tcdefs.h +--- Common/Tcdefs.h.orig ++++ Common/Tcdefs.h +@@ -73,7 +73,7 @@ + #define VERSION_NUM 0x0126 + + // Release date +-#define TC_STR_RELEASE_DATE L"June 8, 2026" ++#define TC_STR_RELEASE_DATE L"June 9, 2026" + #define TC_RELEASE_DATE_YEAR 2026 + #define TC_RELEASE_DATE_MONTH 6 + #define TC_RELEASE_DATE_DAY 9 Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_cpp @@ -0,0 +1,42 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Core/Unix/CoreServiceRequest.cpp.orig ++++ Core/Unix/CoreServiceRequest.cpp +@@ -245,6 +245,27 @@ + } + #endif + ++#ifdef TC_OPENBSD ++ void ExecuteOpenBSDFFSFormatterRequest::Deserialize (shared_ptr stream) ++ { ++ CoreServiceRequest::Deserialize (stream); ++ Serializer sr (stream); ++ Device = sr.DeserializeWString ("Device"); ++ } ++ ++ bool ExecuteOpenBSDFFSFormatterRequest::RequiresElevation () const ++ { ++ return !Core->HasAdminPrivileges(); ++ } ++ ++ void ExecuteOpenBSDFFSFormatterRequest::Serialize (shared_ptr stream) const ++ { ++ CoreServiceRequest::Serialize (stream); ++ Serializer sr (stream); ++ sr.Serialize ("Device", wstring (Device)); ++ } ++#endif ++ + // MountVolumeRequest + void MountVolumeRequest::Deserialize (shared_ptr stream) + { +@@ -326,6 +347,9 @@ + TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetHostDevicesRequest); ++#ifdef TC_OPENBSD ++ TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteOpenBSDFFSFormatterRequest); ++#endif + TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerRequest); + } Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_h =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_h @@ -0,0 +1,22 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Core/Unix/CoreServiceRequest.h.orig ++++ Core/Unix/CoreServiceRequest.h +@@ -142,6 +142,17 @@ + }; + #endif + ++#ifdef TC_OPENBSD ++ struct ExecuteOpenBSDFFSFormatterRequest : CoreServiceRequest ++ { ++ ExecuteOpenBSDFFSFormatterRequest () { } ++ ExecuteOpenBSDFFSFormatterRequest (const DevicePath &devicePath) : Device (devicePath) { } ++ TC_SERIALIZABLE (ExecuteOpenBSDFFSFormatterRequest); ++ virtual bool RequiresElevation () const; ++ DevicePath Device; ++ }; ++#endif ++ + struct MountVolumeRequest : CoreServiceRequest + { + MountVolumeRequest () { } Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_cpp @@ -0,0 +1,32 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Core/Unix/CoreServiceResponse.cpp.orig ++++ Core/Unix/CoreServiceResponse.cpp +@@ -100,6 +100,17 @@ + } + #endif + ++#ifdef TC_OPENBSD ++ void ExecuteOpenBSDFFSFormatterResponse::Deserialize (shared_ptr stream) ++ { ++ } ++ ++ void ExecuteOpenBSDFFSFormatterResponse::Serialize (shared_ptr stream) const ++ { ++ Serializable::Serialize (stream); ++ } ++#endif ++ + // MountVolumeResponse + void MountVolumeResponse::Deserialize (shared_ptr stream) + { +@@ -133,6 +144,9 @@ + #ifdef TC_MACOSX + TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteMacOSXAPFSFormatterResponse); + #endif ++#ifdef TC_OPENBSD ++ TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteOpenBSDFFSFormatterResponse); ++#endif + TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerResponse); + } Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_h =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_h @@ -0,0 +1,18 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Core/Unix/CoreServiceResponse.h.orig ++++ Core/Unix/CoreServiceResponse.h +@@ -77,6 +77,13 @@ + }; + #endif + ++#ifdef TC_OPENBSD ++ struct ExecuteOpenBSDFFSFormatterResponse : CoreServiceResponse ++ { ++ TC_SERIALIZABLE (ExecuteOpenBSDFFSFormatterResponse); ++ }; ++#endif ++ + struct MountVolumeResponse : CoreServiceResponse + { + MountVolumeResponse () { } Index: security/veracrypt/patches/patch-Core_Unix_CoreService_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_Unix_CoreService_cpp @@ -0,0 +1,392 @@ +Use doas with rules restricted to --core-service and a private authentication +terminal. Keep its slave on stderr across doas closefrom(), forward one +password response, and detach the elevated worker before releasing the tty. +Format OpenBSD FFS through a restricted privileged service request. + +--- Core/Unix/CoreService.cpp.orig ++++ Core/Unix/CoreService.cpp +@@ -14,6 +14,15 @@ + #include + #include + #include ++#ifdef TC_OPENBSD ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif + #include "Platform/FileStream.h" + #include "Platform/MemoryStream.h" + #include "Platform/Serializable.h" +@@ -28,6 +37,24 @@ + + namespace VeraCrypt + { ++#ifdef TC_OPENBSD ++ // doas(1) reads the password from its controlling terminal. A private ++ // pseudoterminal is used for that, so the elevated process does not need ++ // a terminal of its own and the password entered in the user interface ++ // can be forwarded without exposing it on the command line or in the ++ // environment. ++ static int DoasAuthTerminalFd = -1; ++ ++ static void CloseDoasAuthTerminal () ++ { ++ if (DoasAuthTerminalFd != -1) ++ { ++ close (DoasAuthTerminalFd); ++ DoasAuthTerminalFd = -1; ++ } ++ } ++#endif ++ + #ifdef TC_MACOSX + static bool IsMacOSXDevicePathWithPrefix (const string &path, const string &prefix) + { +@@ -111,6 +138,10 @@ + { + try + { ++#ifdef TC_OPENBSD ++ // Detach the elevated worker before releasing its auth terminal. ++ throw_sys_if (setsid () == -1); ++#endif + int f = open ("/dev/null", 0); + throw_sys_sub_if (f == -1, "/dev/null"); + throw_sys_if (dup2 (f, STDERR_FILENO) == -1); +@@ -149,6 +180,10 @@ + + void CoreService::ProcessRequests (int inputFD, int outputFD) + { ++#ifdef TC_OPENBSD ++ finally_do ({ CloseDoasAuthTerminal (); }); ++#endif ++ + try + { + Core = move_ptr(CoreDirect); +@@ -273,6 +308,34 @@ + } + #endif + ++#ifdef TC_OPENBSD ++ ExecuteOpenBSDFFSFormatterRequest *formatRequest = dynamic_cast (request.get()); ++ if (formatRequest) ++ { ++ string device = formatRequest->Device; ++ if (device.size() != 10 || device.compare (0, 8, "/dev/vnd") != 0 ++ || device[8] < '0' || device[8] > '3' || device[9] != 'c') ++ throw ParameterIncorrect (SRC_POS); ++ ++ // Format only a VeraCrypt virtual device without a mounted ++ // filesystem, never an arbitrary host disk or active filesystem. ++ bool mountedVolumeFound = false; ++ foreach (shared_ptr volume, Core->GetMountedVolumes()) ++ { ++ if (volume->VirtualDevice == formatRequest->Device && volume->MountPoint.IsEmpty()) ++ mountedVolumeFound = true; ++ } ++ if (!mountedVolumeFound) ++ throw ParameterIncorrect (SRC_POS); ++ ++ list arguments; ++ arguments.push_back ("/dev/r" + device.substr (5)); ++ Process::Execute ("/sbin/newfs", arguments); ++ ExecuteOpenBSDFFSFormatterResponse().Serialize (outputStream); ++ continue; ++ } ++#endif ++ + // MountVolumeRequest + MountVolumeRequest *mountRequest = dynamic_cast (request.get()); + if (mountRequest) +@@ -372,6 +435,14 @@ + { + ExecuteMacOSXAPFSFormatterRequest request (devicePath, userId, groupId); + SendRequest (request); ++ } ++#endif ++ ++#ifdef TC_OPENBSD ++ void CoreService::RequestExecuteOpenBSDFFSFormatter (const DevicePath &devicePath) ++ { ++ ExecuteOpenBSDFFSFormatterRequest request (devicePath); ++ SendRequest (request); + } + #endif + +@@ -408,6 +479,7 @@ + { + // Test if the user has an active "sudo" session. + bool authCheckDone = false; ++#ifndef TC_OPENBSD + if (!Core->GetUseDummySudoPassword ()) + { + // We are using -n to avoid prompting the user for a password. +@@ -452,6 +524,9 @@ + request.FastElevation = false; + } + } ++#endif ++ // On OpenBSD, test the actual service with doas -n. A rule ++ // restricted to --core-service need not allow /usr/bin/true. + + try + { +@@ -507,6 +582,36 @@ + + void CoreService::StartElevated (const CoreServiceRequest &request) + { ++#ifdef TC_OPENBSD ++ CloseDoasAuthTerminal(); ++ ++ int authTerminalFd = -1; ++ string authTerminalPath; ++ bool authTerminalKept = false; ++ ++ finally_do_arg2 (int *, &authTerminalFd, bool *, &authTerminalKept, ++ { ++ if (!*finally_arg2 && *finally_arg != -1) ++ { ++ close (*finally_arg); ++ *finally_arg = -1; ++ } ++ }); ++ ++ if (!request.FastElevation) ++ { ++ authTerminalFd = posix_openpt (O_RDWR | O_NOCTTY); ++ throw_sys_sub_if (authTerminalFd == -1, "posix_openpt"); ++ throw_sys_if (fcntl (authTerminalFd, F_SETFD, FD_CLOEXEC) == -1); ++ throw_sys_if (grantpt (authTerminalFd) == -1); ++ throw_sys_if (unlockpt (authTerminalFd) == -1); ++ ++ char *slavePath = ptsname (authTerminalFd); ++ throw_sys_sub_if (slavePath == nullptr, "ptsname"); ++ authTerminalPath = slavePath; ++ } ++#endif ++ + unique_ptr inPipe (new Pipe()); + unique_ptr outPipe (new Pipe()); + Pipe errPipe; +@@ -522,7 +627,11 @@ + { + // Throw exception if sudo is not found in secure locations + std::string errorMsg; ++#ifdef TC_OPENBSD ++ string sudoPath = Process::FindSystemBinary("doas", errorMsg); ++#else + string sudoPath = Process::FindSystemBinary("sudo", errorMsg); ++#endif + if (sudoPath.empty()) + throw SystemException(SRC_POS, errorMsg); + +@@ -551,7 +660,54 @@ + throw_sys_if (dup2 (outPipe->GetWriteFD(), STDOUT_FILENO) == -1); + throw_sys_if (dup2 (errPipe.GetWriteFD(), STDERR_FILENO) == -1); + ++#ifdef TC_OPENBSD ++ const char *args[8]; ++ ++ if (!authTerminalPath.empty()) ++ { ++ throw_sys_if (setsid () == -1); ++ ++ int authFd = open (authTerminalPath.c_str(), O_RDWR); ++ throw_sys_sub_if (authFd == -1, authTerminalPath); ++ ++ // Keep the admin password out of the terminal echo. ++ struct termios tios; ++ throw_sys_if (tcgetattr (authFd, &tios) == -1); ++ { ++ tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN); ++ tios.c_iflag &= ~(BRKINT | ISTRIP | INLCR | IGNCR | ICRNL | IXON); ++ tios.c_cc[VMIN] = 1; ++ tios.c_cc[VTIME] = 0; ++ throw_sys_if (tcsetattr (authFd, TCSANOW, &tios) == -1); ++ } ++ ++ if (ioctl (authFd, TIOCSCTTY, 0) == -1 && errno != EINVAL) ++ { ++ close (authFd); ++ throw SystemException (SRC_POS, "TIOCSCTTY"); ++ } ++ ++ // doas closes descriptors above stderr before authentication. ++ // Keep the slave on stderr so /dev/tty remains available. ++ throw_sys_if (dup2 (authFd, STDERR_FILENO) == -1); ++ close (authFd); ++ ++ args[0] = sudoPath.c_str(); ++ args[1] = appPath.c_str(); ++ args[2] = TC_CORE_SERVICE_CMDLINE_OPTION; ++ args[3] = nullptr; ++ } ++ else ++ { ++ args[0] = sudoPath.c_str(); ++ args[1] = "-n"; ++ args[2] = appPath.c_str(); ++ args[3] = TC_CORE_SERVICE_CMDLINE_OPTION; ++ args[4] = nullptr; ++ } ++#else + const char *args[] = { sudoPath.c_str(), "-S", "-p", "", appPath.c_str(), TC_CORE_SERVICE_CMDLINE_OPTION, nullptr }; ++#endif + execvp (args[0], ((char* const*) args)); + throw SystemException (SRC_POS, args[0]); + } +@@ -601,9 +757,13 @@ + #if defined(TC_LINUX ) + Thread::Sleep (1000); // wait 1 second for the forked sudo to start + #endif ++#ifndef TC_OPENBSD + if (write (inPipe->GetWriteFD(), &adminPassword.front(), adminPassword.size())) { } // Errors ignored +- +- burn (&adminPassword.front(), adminPassword.size()); ++#endif ++ finally_do_arg (vector *, &adminPassword, ++ { ++ burn (&finally_arg->front(), finally_arg->size()); ++ }); + + throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, O_NONBLOCK) == -1); + throw_sys_if (fcntl (errPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1); +@@ -611,11 +771,77 @@ + char buffer[4096]; + vector errOutput; + errOutput.reserve (4096); ++#ifdef TC_OPENBSD ++ vector authOutput; ++#endif + + Poller poller (outPipe->GetReadFD(), errPipe.GetReadFD()); + int status, waitRes; + int exitCode = 1; + ++#ifdef TC_OPENBSD ++ if (authTerminalFd != -1) ++ { ++ throw_sys_if (fcntl (authTerminalFd, F_SETFL, O_NONBLOCK) == -1); ++ Poller authPoller (outPipe->GetReadFD(), errPipe.GetReadFD(), authTerminalFd); ++ bool passwordSent = false; ++ ++ while ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0) ++ { ++ list ready; ++ try ++ { ++ ready = authPoller.WaitForData (timeout); ++ } ++ catch (TimeOut&) ++ { ++ kill (forkedPid, SIGTERM); ++ close (authTerminalFd); ++ authTerminalFd = -1; ++ waitpid (forkedPid, &status, 0); ++ throw ElevationFailed (SRC_POS, "doas", 1, "Authentication timed out"); ++ } ++ ++ foreach (int fd, ready) ++ { ++ ssize_t bytesRead = read (fd, buffer, sizeof (buffer)); ++ if (bytesRead <= 0) ++ continue; ++ ++ if (fd == errPipe.GetReadFD()) ++ errOutput.insert (errOutput.end(), buffer, buffer + bytesRead); ++ ++ if (fd == authTerminalFd) ++ { ++ authOutput.insert (authOutput.end(), buffer, buffer + bytesRead); ++ if (!passwordSent) ++ { ++ // readpassphrase has opened the terminal and printed its prompt. ++ size_t sent = 0; ++ while (sent < adminPassword.size()) ++ { ++ ssize_t n = write (authTerminalFd, &adminPassword[sent], adminPassword.size() - sent); ++ if (n < 0 && errno == EINTR) ++ continue; ++ throw_sys_if (n <= 0); ++ sent += n; ++ } ++ burn (&adminPassword.front(), adminPassword.size()); ++ passwordSent = true; ++ } ++ else if (string (authOutput.begin(), authOutput.end()).find ("Authentication failed") != string::npos) ++ { ++ // Let the frontend request a new password, rather than leaving ++ // doas waiting for another response on its private terminal. ++ kill (forkedPid, SIGTERM); ++ } ++ } ++ } ++ } ++ } ++ else ++#endif ++ { + try + { + do +@@ -667,11 +893,17 @@ + Thread thread; + thread.Start (new WaitFunctor (forkedPid)); + ++#ifdef TC_OPENBSD ++ throw ElevationFailed (SRC_POS, "doas", 1, ""); ++#else + throw ElevationFailed (SRC_POS, "sudo", 1, ""); ++#endif + } + + waitRes = waitpid (forkedPid, &status, 0); + } ++ } ++ + } + + if (!errOutput.empty()) +@@ -700,11 +932,19 @@ + if (!errOutput.empty()) + strErrOutput.insert (strErrOutput.begin(), errOutput.begin(), errOutput.end()); + ++#ifdef TC_OPENBSD ++ strErrOutput.insert (strErrOutput.end(), authOutput.begin(), authOutput.end()); ++ if (strErrOutput.find (" tty") != string::npos) ++ strErrOutput += "\nTo allow VeraCrypt to elevate privileges, add an appropriate rule for it to '/etc/doas.conf'."; ++ ++ throw ElevationFailed (SRC_POS, "doas", exitCode, strErrOutput); ++#else + // sudo may require a tty even if -S is used + if (strErrOutput.find (" tty") != string::npos) + strErrOutput += "\nTo enable use of 'sudo' by applications without a terminal window, please disable 'requiretty' option in '/etc/sudoers'. Newer versions of sudo automatically determine whether a terminal is required ('requiretty' option is obsolete)."; + + throw ElevationFailed (SRC_POS, "sudo", exitCode, strErrOutput); ++#endif + } + + throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, 0) == -1); +@@ -718,6 +958,17 @@ + + AdminInputPipe = move_ptr(inPipe); + AdminOutputPipe = move_ptr(outPipe); ++ ++#ifdef TC_OPENBSD ++ if (authTerminalFd != -1) ++ { ++ // Keep the authentication terminal open for the lifetime of the ++ // elevated service. Closing the master would hang up the service. ++ authTerminalKept = true; ++ DoasAuthTerminalFd = authTerminalFd; ++ authTerminalFd = -1; ++ } ++#endif + } + + void CoreService::Stop () Index: security/veracrypt/patches/patch-Core_Unix_CoreService_h =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_Unix_CoreService_h @@ -0,0 +1,14 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Core/Unix/CoreService.h.orig ++++ Core/Unix/CoreService.h +@@ -39,6 +39,9 @@ + static const char *GetMacOSXAPFSFormatterPath (); + static void RequestExecuteMacOSXAPFSFormatter (const DevicePath &devicePath, uint64 userId, uint64 groupId); + #endif ++#ifdef TC_OPENBSD ++ static void RequestExecuteOpenBSDFFSFormatter (const DevicePath &devicePath); ++#endif + static shared_ptr RequestMountVolume (MountOptions &options); + static void RequestSetFileOwner (const FilesystemPath &path, const UserId &owner); + static void SetAdminPasswordCallback (shared_ptr functor) { AdminPasswordCallback = functor; } Index: security/veracrypt/patches/patch-Core_VolumeCreator_h =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Core_VolumeCreator_h @@ -0,0 +1,34 @@ +Represent FFS as the OpenBSD native filesystem and select /sbin/newfs +for its formatter. + +Index: Core/VolumeCreator.h +--- Core/VolumeCreator.h.orig ++++ Core/VolumeCreator.h +@@ -55,7 +55,8 @@ + Btrfs, + MacOsExt, + APFS, +- UFS ++ UFS, ++ FFS + }; + + static Enum GetPlatformNative () +@@ -68,6 +69,8 @@ + return VolumeCreationOptions::FilesystemType::MacOsExt; + #elif defined (TC_FREEBSD) || defined (TC_SOLARIS) + return VolumeCreationOptions::FilesystemType::UFS; ++#elif defined (TC_OPENBSD) ++ return VolumeCreationOptions::FilesystemType::FFS; + #else + return VolumeCreationOptions::FilesystemType::FAT; + #endif +@@ -90,6 +93,8 @@ + case VolumeCreationOptions::FilesystemType::APFS: return "newfs_apfs"; + #elif defined (TC_FREEBSD) || defined (TC_SOLARIS) + case VolumeCreationOptions::FilesystemType::UFS: return "newfs" ; ++ #elif defined (TC_OPENBSD) ++ case VolumeCreationOptions::FilesystemType::FFS: return "/sbin/newfs" ; + #endif + default: return NULL; + } Index: security/veracrypt/patches/patch-Main_CommandLineInterface_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Main_CommandLineInterface_cpp @@ -0,0 +1,15 @@ +Accept FFS as an explicit filesystem selection on the OpenBSD CLI. + +Index: Main/CommandLineInterface.cpp +--- Main/CommandLineInterface.cpp.orig ++++ Main/CommandLineInterface.cpp +@@ -415,6 +415,9 @@ + 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)) ++ ArgFilesystem = VolumeCreationOptions::FilesystemType::FFS; + #endif + else + throw_err (LangString["UNKNOWN_OPTION"] + L": " + str); Index: security/veracrypt/patches/patch-Main_Forms_VolumeCreationWizard_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Main_Forms_VolumeCreationWizard_cpp @@ -0,0 +1,32 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Main/Forms/VolumeCreationWizard.cpp.orig ++++ Main/Forms/VolumeCreationWizard.cpp +@@ -17,6 +17,9 @@ + #include + #include // header for statvfs + #include "Platform/Unix/Process.h" ++#endif ++#ifdef TC_OPENBSD ++#include "Core/Unix/CoreService.h" + #endif + #include "Core/RandomNumberGenerator.h" + #include "Core/VolumeCreator.h" +@@ -869,7 +872,7 @@ + bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter); + if (!useElevatedAPFSFormatter) + PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners); +-#else ++#elif !defined(TC_OPENBSD) + UserId origDeviceOwner ((uid_t) -1); + + try +@@ -926,6 +929,8 @@ + SetCreationProgressText (StringFormatter (LangString["FORMAT_STAGE_CREATING_FILESYSTEM"], fsFormatter)); + #ifdef TC_MACOSX + ExecuteMacOSXFilesystemFormatter (fsFormatter, args); ++#elif defined(TC_OPENBSD) ++ CoreService::RequestExecuteOpenBSDFFSFormatter (virtualDevice); + #else + Process::Execute (fsFormatter, args); + #endif Index: security/veracrypt/patches/patch-Main_Forms_VolumeFormatOptionsWizardPage_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Main_Forms_VolumeFormatOptionsWizardPage_cpp @@ -0,0 +1,23 @@ +Offer FFS in the OpenBSD GUI filesystem selector and restore that +selection when displaying existing creation options. + +Index: Main/Forms/VolumeFormatOptionsWizardPage.cpp +--- Main/Forms/VolumeFormatOptionsWizardPage.cpp.orig ++++ Main/Forms/VolumeFormatOptionsWizardPage.cpp +@@ -52,6 +52,8 @@ + 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 @@ + 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); Index: security/veracrypt/patches/patch-Main_TextUserInterface_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Main_TextUserInterface_cpp @@ -0,0 +1,55 @@ +Run OpenBSD FFS formatting through the elevated core service. + +--- Main/TextUserInterface.cpp.orig ++++ Main/TextUserInterface.cpp +@@ -24,6 +24,9 @@ + #include "Common/Token.h" + #include "Common/SecurityToken.h" + #include "Common/EMVToken.h" ++#ifdef TC_OPENBSD ++#include "Core/Unix/CoreService.h" ++#endif + #include "Core/RandomNumberGenerator.h" + #include "Application.h" + #ifdef TC_MACOSX +@@ -930,7 +933,13 @@ + { + 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 + { +@@ -971,6 +980,8 @@ + } + #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; +@@ -1132,7 +1143,7 @@ + bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter); + if (!useElevatedAPFSFormatter) + PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners); +-#else ++#elif !defined(TC_OPENBSD) + UserId origDeviceOwner ((uid_t) -1); + + try +@@ -1188,6 +1199,8 @@ + + #ifdef TC_MACOSX + ExecuteMacOSXFilesystemFormatter (fsFormatter, args); ++#elif defined(TC_OPENBSD) ++ CoreService::RequestExecuteOpenBSDFFSFormatter (virtualDevice); + #else + Process::Execute (fsFormatter, args); + #endif Index: security/veracrypt/patches/patch-Main_UserInterface_cpp =================================================================== --- /dev/null +++ security/veracrypt/patches/patch-Main_UserInterface_cpp @@ -0,0 +1,18 @@ +Name doas in OpenBSD elevation failures to match the core service +launcher, retaining sudo diagnostics on other platforms. + +Index: Main/UserInterface.cpp +--- Main/UserInterface.cpp.orig ++++ Main/UserInterface.cpp +@@ -40,7 +40,11 @@ + public: + virtual void operator() (string &str) + { ++#ifdef TC_OPENBSD ++ throw ElevationFailed (SRC_POS, "doas", 1, ""); ++#else + throw ElevationFailed (SRC_POS, "sudo", 1, ""); ++#endif + } + }; + Index: security/veracrypt/pkg/README =================================================================== --- /dev/null +++ security/veracrypt/pkg/README @@ -0,0 +1,35 @@ ++------------------------------------------------------------------------------- +| Running ${PKGSTEM} on OpenBSD ++------------------------------------------------------------------------------- + +Privilege elevation +=================== + +VeraCrypt runs its privileged core service through doas(1). Add a rule to +/etc/doas.conf before mounting, creating or formatting volumes: + + permit :wheel cmd ${TRUEPREFIX}/bin/veracrypt args --core-service + +This rule permits only the privileged core service used internally by +VeraCrypt. Run the normal CLI or GUI as your own user. Do not use +"permit nopass" unless you accept passwordless elevation for every user +allowed by the rule. + +The core service is used for operations that require root privileges, such as +configuring vnd(4) loop devices, mounting and unmounting filesystems, +changing ownership of mount points and device nodes, and running newfs(8) +when an OpenBSD FFS filesystem is created inside a volume. + +Filesystem creation +=================== + +OpenBSD FFS filesystems can be created inside a new volume by selecting the +"FFS" filesystem in the volume creation wizard or by passing +"--filesystem=FFS" on the command line. The filesystem is created with +newfs(8) on the raw vnd(4) character device through the elevated core +service. Changing device ownership alone is insufficient: reading the disk +label requires privileged ioctls on OpenBSD. + +Noninteractive creation retains FAT as its default. Request FFS explicitly +with --filesystem=FFS. Without a passwordless doas rule, use interactive mode +so VeraCrypt can request your account password. Index: security/veracrypt/patches/patch-Core_Unix_OpenBSD_CoreOpenBSD_cpp =================================================================== --- security/veracrypt/patches/patch-Core_Unix_OpenBSD_CoreOpenBSD_cpp +++ /dev/null @@ -1,14 +0,0 @@ -The -c option is no more. https://github.com/veracrypt/VeraCrypt/pull/1002 - -Index: Core/Unix/OpenBSD/CoreOpenBSD.cpp ---- Core/Unix/OpenBSD/CoreOpenBSD.cpp.orig -+++ Core/Unix/OpenBSD/CoreOpenBSD.cpp -@@ -69,8 +69,6 @@ namespace VeraCrypt - if (freeVnd == -1) - throw "couldn't find free vnd"; - -- args.push_back ("-c"); -- - stringstream freePath; - freePath << "vnd" << freeVnd; - args.push_back (freePath.str());