Skip to content

Commit 47786dd

Browse files
committed
Unix: add doas elevation support
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.
1 parent 26adb5e commit 47786dd

8 files changed

Lines changed: 623 additions & 131 deletions

File tree

src/Core/Unix/CoreService.cpp

Lines changed: 529 additions & 75 deletions
Large diffs are not rendered by default.

src/Core/Unix/CoreService.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace VeraCrypt
2424
class CoreService
2525
{
2626
public:
27-
static void ProcessElevatedRequests ();
27+
static void ProcessElevatedRequests (bool forkProcess = true);
2828
static void ProcessRequests (int inputFD = -1, int outputFD = -1);
2929
static void RequestCheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair);
3030
static void RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force);
@@ -70,6 +70,7 @@ namespace VeraCrypt
7070
};
7171

7272
#define TC_CORE_SERVICE_CMDLINE_OPTION "--core-service"
73+
#define TC_CORE_SERVICE_NO_FORK_CMDLINE_OPTION "--core-service-no-fork"
7374
}
7475

7576
#endif // TC_HEADER_Core_Unix_CoreService

src/Core/Unix/CoreUnix.cpp

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,12 @@
2121
#ifdef TC_LINUX
2222
#include <sys/utsname.h>
2323
#endif
24-
#ifdef TC_OPENBSD
25-
#include <pwd.h>
26-
#endif
2724
#include <stdio.h>
2825
#include <unistd.h>
2926
#include "Platform/FileStream.h"
3027
#include "Platform/MemoryStream.h"
3128
#include "Platform/SystemLog.h"
29+
#include "Core/Unix/UnixUser.h"
3230
#include "Driver/Fuse/FuseService.h"
3331
#include "Volume/VolumePasswordCache.h"
3432

@@ -43,26 +41,6 @@ namespace VeraCrypt
4341
static bool SamePath (const string& path1, const string& path2);
4442
#endif
4543

46-
#ifdef TC_OPENBSD
47-
static bool GetDoasUserIds (uid_t *uid, gid_t *gid)
48-
{
49-
const char *env = getenv ("DOAS_USER");
50-
if (!env || !env[0])
51-
return false;
52-
53-
struct passwd *pw = getpwnam (env);
54-
if (!pw)
55-
return false;
56-
57-
if (uid)
58-
*uid = pw->pw_uid;
59-
if (gid)
60-
*gid = pw->pw_gid;
61-
62-
return true;
63-
}
64-
#endif
65-
6644
// Struct to hold terminal emulator information
6745
struct TerminalInfo {
6846
const char* name;
@@ -657,11 +635,9 @@ namespace VeraCrypt
657635
catch (...) { }
658636
}
659637

660-
#ifdef TC_OPENBSD
661638
gid_t doasGid;
662639
if (GetDoasUserIds (nullptr, &doasGid))
663640
return doasGid;
664-
#endif
665641

666642
return getgid();
667643
}
@@ -679,11 +655,9 @@ namespace VeraCrypt
679655
catch (...) { }
680656
}
681657

682-
#ifdef TC_OPENBSD
683658
uid_t doasUid;
684659
if (GetDoasUserIds (&doasUid, nullptr))
685660
return doasUid;
686-
#endif
687661

688662
return getuid();
689663
}

src/Core/Unix/UnixUser.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Derived from source code of TrueCrypt 7.1a, which is
3+
Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
4+
by the TrueCrypt License 3.0.
5+
6+
Modifications and additions to the original source code (contained in this file)
7+
and all other portions of this file are Copyright (c) 2013-2026 AM Crypto
8+
and are governed by the Apache License 2.0 the full text of which is
9+
contained in the file License.txt included in VeraCrypt binary and source
10+
code distribution packages.
11+
*/
12+
13+
#ifndef TC_HEADER_Core_Unix_UnixUser
14+
#define TC_HEADER_Core_Unix_UnixUser
15+
16+
#include <errno.h>
17+
#include <pwd.h>
18+
#include <stdlib.h>
19+
#include <string.h>
20+
#include <sys/types.h>
21+
#include <unistd.h>
22+
#include <vector>
23+
24+
#define TC_DOAS_CORE_SERVICE_ENV "VERACRYPT_DOAS_CORE_SERVICE"
25+
26+
namespace VeraCrypt
27+
{
28+
static inline bool GetDoasUserIds (uid_t *uid, gid_t *gid)
29+
{
30+
if (getuid () != 0 || geteuid () != 0 || getenv ("SUDO_UID") || getenv ("SUDO_GID"))
31+
return false;
32+
33+
#ifndef TC_OPENBSD
34+
const char *trustedDoasService = getenv (TC_DOAS_CORE_SERVICE_ENV);
35+
if (!trustedDoasService || strcmp (trustedDoasService, "1") != 0)
36+
return false;
37+
#endif
38+
39+
const char *env = getenv ("DOAS_USER");
40+
if (!env || !env[0])
41+
return false;
42+
43+
long bufferSize = 16384;
44+
#ifdef _SC_GETPW_R_SIZE_MAX
45+
long sysconfBufferSize = sysconf (_SC_GETPW_R_SIZE_MAX);
46+
if (sysconfBufferSize > 0)
47+
bufferSize = sysconfBufferSize;
48+
#endif
49+
50+
struct passwd pw;
51+
struct passwd *pwResult = nullptr;
52+
std::vector <char> buffer (static_cast <size_t> (bufferSize));
53+
int status;
54+
55+
while ((status = getpwnam_r (env, &pw, &buffer[0], buffer.size(), &pwResult)) == ERANGE)
56+
{
57+
if (buffer.size () > 1024 * 1024)
58+
return false;
59+
buffer.resize (buffer.size () * 2);
60+
}
61+
62+
if (status != 0 || !pwResult)
63+
return false;
64+
65+
if (uid)
66+
*uid = pw.pw_uid;
67+
if (gid)
68+
*gid = pw.pw_gid;
69+
70+
return true;
71+
}
72+
}
73+
74+
#endif // TC_HEADER_Core_Unix_UnixUser

src/Driver/Fuse/FuseService.cpp

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@
4040
#include <stdio.h>
4141
#include <unistd.h>
4242
#include <time.h>
43-
#ifdef TC_OPENBSD
44-
#include <pwd.h>
45-
#endif
4643
#include <sys/mman.h>
4744
#include <sys/statvfs.h>
4845
#include <sys/time.h>
@@ -55,6 +52,7 @@
5552
#include "Platform/SystemLog.h"
5653
#include "Platform/Unix/Pipe.h"
5754
#include "Platform/Unix/Poller.h"
55+
#include "Core/Unix/UnixUser.h"
5856
#include "Volume/EncryptionThreadPool.h"
5957
#include "Core/Core.h"
6058

@@ -68,26 +66,6 @@ namespace VeraCrypt
6866
static const uint64 VC_FUSE_METADATA_SIZE = 64 * 1024;
6967
static const uint64 VC_FUSE_STAT_BLOCK_SIZE = 512;
7068

71-
#ifdef TC_OPENBSD
72-
static bool fuse_service_get_doas_user_ids (uid_t *uid, gid_t *gid)
73-
{
74-
const char *env = getenv ("DOAS_USER");
75-
if (!env || !env[0])
76-
return false;
77-
78-
struct passwd *pw = getpwnam (env);
79-
if (!pw)
80-
return false;
81-
82-
if (uid)
83-
*uid = pw->pw_uid;
84-
if (gid)
85-
*gid = pw->pw_gid;
86-
87-
return true;
88-
}
89-
#endif
90-
9169
static uint64 fuse_service_ceil_div (uint64 value, uint64 divisor)
9270
{
9371
return (value / divisor) + ((value % divisor) ? 1 : 0);
@@ -813,18 +791,16 @@ namespace VeraCrypt
813791
}
814792
catch (...) { }
815793
}
816-
#ifdef TC_OPENBSD
817794
else
818795
{
819796
uid_t doasUid;
820797
gid_t doasGid;
821-
if (fuse_service_get_doas_user_ids (&doasUid, &doasGid))
798+
if (GetDoasUserIds (&doasUid, &doasGid))
822799
{
823800
FuseService::UserId = doasUid;
824801
FuseService::GroupId = doasGid;
825802
}
826803
}
827-
#endif
828804

829805
static fuse_operations fuse_service_oper;
830806

src/Main/Unix/Main.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "Platform/SystemLog.h"
1818
#include "Volume/EncryptionThreadPool.h"
1919
#include "Core/Unix/CoreService.h"
20+
#include "Core/Unix/UnixUser.h"
2021
#include "Main/Application.h"
2122
#include "Main/Main.h"
2223
#include "Main/UserInterface.h"
@@ -43,12 +44,16 @@ int main (int argc, char **argv)
4344

4445
setenv ("PATH", sysPathStr.c_str(), 1);
4546

46-
if (argc > 1 && strcmp (argv[1], TC_CORE_SERVICE_CMDLINE_OPTION) == 0)
47+
if (argc > 1 && (strcmp (argv[1], TC_CORE_SERVICE_CMDLINE_OPTION) == 0 || strcmp (argv[1], TC_CORE_SERVICE_NO_FORK_CMDLINE_OPTION) == 0))
4748
{
4849
// Process elevated requests
4950
try
5051
{
51-
CoreService::ProcessElevatedRequests();
52+
bool forkProcess = strcmp (argv[1], TC_CORE_SERVICE_CMDLINE_OPTION) == 0;
53+
if (!forkProcess)
54+
setenv (TC_DOAS_CORE_SERVICE_ENV, "1", 1);
55+
56+
CoreService::ProcessElevatedRequests (forkProcess);
5257
return 0;
5358
}
5459
catch (exception &e)

src/Platform/Thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace VeraCrypt
4141
virtual ~Thread () { };
4242

4343
void Join () const;
44+
void Detach () const;
4445
void Start (ThreadProcPtr threadProc, void *parameter = nullptr);
4546

4647
void Start (Functor *functor)

src/Platform/Unix/Thread.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ namespace VeraCrypt
4545
throw SystemException (SRC_POS, status);
4646
}
4747

48+
void Thread::Detach () const
49+
{
50+
int status = pthread_detach (SystemHandle);
51+
if (status != 0)
52+
throw SystemException (SRC_POS, status);
53+
}
54+
4855
void Thread::Start (ThreadProcPtr threadProc, void *parameter)
4956
{
5057
PthreadAttr attr;

0 commit comments

Comments
 (0)