2
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, either version 2 or (at your option)
7
* version 3 of the License.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#include "config-keepassx.h"
20
#include "core/Translator.h"
23
#include <aclapi.h> // for createWindowsDACL()
24
#include <windows.h> // for Sleep(), SetDllDirectoryA(), SetSearchPathMode(), ...
28
#if defined(HAVE_RLIMIT_CORE)
29
#include <sys/resource.h>
32
#if defined(HAVE_PR_SET_DUMPABLE)
36
#ifdef HAVE_PT_DENY_ATTACH
39
#include <sys/ptrace.h>
46
* When QNetworkAccessManager is instantiated it regularly starts polling
47
* all network interfaces to see if anything changes and if so, what. This
48
* creates a latency spike every 10 seconds on Mac OS 10.12+ and Windows 7 >=
49
* when on a wifi connection.
50
* So here we disable it for lack of better measure.
51
* This will also cause this message: QObject::startTimer: Timers cannot
52
* have negative intervals
54
* - https://bugreports.qt.io/browse/QTBUG-40332
55
* - https://bugreports.qt.io/browse/QTBUG-46015
57
static inline void applyEarlyQNetworkAccessManagerWorkaround()
59
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
63
* Perform early application bootstrapping that does not rely on a QApplication
66
void bootstrap(const QString& uiLanguage)
73
applyEarlyQNetworkAccessManagerWorkaround();
75
Translator::installTranslators(uiLanguage);
79
void disableCoreDumps()
82
// there is no point in printing a warning if this is not implemented on the platform
85
#if defined(HAVE_RLIMIT_CORE)
89
success = success && (setrlimit(RLIMIT_CORE, &limit) == 0);
92
// NOTE: Dumps cannot be disabled for snap builds as it prevents desktop portals from working
93
// See https://github.com/keepassxreboot/keepassxc/issues/7607#issuecomment-1109005206
94
#if defined(HAVE_PR_SET_DUMPABLE) && !defined(KEEPASSXC_DIST_SNAP)
95
success = success && (prctl(PR_SET_DUMPABLE, 0) == 0);
99
#ifdef HAVE_PT_DENY_ATTACH
100
success = success && (ptrace(PT_DENY_ATTACH, 0, 0, 0) == 0);
104
success = success && createWindowsDACL();
108
qWarning("Unable to disable core dumps.");
113
// This function grants the user associated with the process token minimal access rights and
114
// denies everything else on Windows. This includes PROCESS_QUERY_INFORMATION and
115
// PROCESS_VM_READ access rights that are required for MiniDumpWriteDump() or ReadProcessMemory().
116
// We do this using a discretionary access control list (DACL). Effectively this prevents
117
// crash dumps and disallows other processes from accessing our memory. This works as long
118
// as you do not have admin privileges, since then you are able to grant yourself the
119
// SeDebugPrivilege or SeTakeOwnershipPrivilege and circumvent the DACL.
121
bool createWindowsDACL()
123
bool bSuccess = false;
126
// Process token and user
127
HANDLE hToken = nullptr;
128
PTOKEN_USER pTokenUser = nullptr;
129
DWORD cbBufferSize = 0;
130
PSID pLocalSystemSid = nullptr;
131
DWORD pLocalSystemSidSize = SECURITY_MAX_SID_SIZE;
132
PSID pOwnerRightsSid = nullptr;
133
DWORD pOwnerRightsSidSize = SECURITY_MAX_SID_SIZE;
135
// Access control list
139
// Open the access token associated with the calling process
140
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
144
// Retrieve the token information in a TOKEN_USER structure
145
GetTokenInformation(hToken, TokenUser, nullptr, 0, &cbBufferSize);
147
pTokenUser = static_cast<PTOKEN_USER>(HeapAlloc(GetProcessHeap(), 0, cbBufferSize));
148
if (pTokenUser == nullptr) {
152
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, cbBufferSize, &cbBufferSize)) {
156
if (!IsValidSid(pTokenUser->User.Sid)) {
160
// Retrieve LocalSystem account SID
161
pLocalSystemSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pLocalSystemSidSize));
162
if (pLocalSystemSid == nullptr) {
166
if (!CreateWellKnownSid(WinLocalSystemSid, nullptr, pLocalSystemSid, &pLocalSystemSidSize)) {
170
// Retrieve CreaterOwnerRights SID
171
pOwnerRightsSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pOwnerRightsSidSize));
172
if (pOwnerRightsSid == nullptr) {
176
if (!CreateWellKnownSid(WinCreatorOwnerRightsSid, nullptr, pOwnerRightsSid, &pOwnerRightsSidSize)) {
177
auto error = GetLastError();
181
// Calculate the amount of memory that must be allocated for the DACL
182
cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid)
183
+ sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pLocalSystemSid) + GetLengthSid(pOwnerRightsSid);
185
// Create and initialize an ACL
186
pACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(), 0, cbACL));
187
if (pACL == nullptr) {
191
if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
195
// Add allowed access control entries, everything else is denied
196
if (!AddAccessAllowedAce(
199
SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, // same as protected process
200
pTokenUser->User.Sid // pointer to the trustee's SID
205
// Explicitly set "Process Owner" rights to Read Only. The default is Full Control.
206
if (!AddAccessAllowedAce(pACL, ACL_REVISION, READ_CONTROL, pOwnerRightsSid)) {
210
#ifdef WITH_XC_SSHAGENT
211
// OpenSSH for Windows ssh-agent service is running as LocalSystem
212
if (!AddAccessAllowedAce(pACL,
214
PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, // just enough for ssh-agent
215
pLocalSystemSid // known LocalSystem sid
221
// Set discretionary access control list
222
bSuccess = ERROR_SUCCESS
223
== SetSecurityInfo(GetCurrentProcess(), // object handle
224
SE_KERNEL_OBJECT, // type of object
225
DACL_SECURITY_INFORMATION, // change only the objects DACL
227
nullptr, // do not change owner or group
228
pACL, // DACL specified
229
nullptr // do not change SACL
235
HeapFree(GetProcessHeap(), 0, pACL);
237
if (pLocalSystemSid) {
238
HeapFree(GetProcessHeap(), 0, pLocalSystemSid);
240
if (pOwnerRightsSid) {
241
HeapFree(GetProcessHeap(), 0, pOwnerRightsSid);
244
HeapFree(GetProcessHeap(), 0, pTokenUser);
255
void setupSearchPaths()
258
// Make sure Windows doesn't load DLLs from the current working directory
259
SetDllDirectoryA("");
260
SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
264
} // namespace Bootstrap