-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy pathBootstrap.cpp
265 lines (226 loc) · 8.85 KB
/
Bootstrap.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Bootstrap.h"
#include "config-keepassx.h"
#include "core/Translator.h"
#ifdef Q_OS_WIN
#include <aclapi.h> // for createWindowsDACL()
#include <windows.h> // for Sleep(), SetDllDirectoryA(), SetSearchPathMode(), ...
#undef MessageBox
#endif
#if defined(HAVE_RLIMIT_CORE)
#include <sys/resource.h>
#endif
#if defined(HAVE_PR_SET_DUMPABLE)
#include <sys/prctl.h>
#endif
#ifdef HAVE_PT_DENY_ATTACH
// clang-format off
#include <sys/types.h>
#include <sys/ptrace.h>
// clang-format on
#endif
namespace Bootstrap
{
/**
* When QNetworkAccessManager is instantiated it regularly starts polling
* all network interfaces to see if anything changes and if so, what. This
* creates a latency spike every 10 seconds on Mac OS 10.12+ and Windows 7 >=
* when on a wifi connection.
* So here we disable it for lack of better measure.
* This will also cause this message: QObject::startTimer: Timers cannot
* have negative intervals
* For more info see:
* - https://bugreports.qt.io/browse/QTBUG-40332
* - https://bugreports.qt.io/browse/QTBUG-46015
*/
static inline void applyEarlyQNetworkAccessManagerWorkaround()
{
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
}
/**
* Perform early application bootstrapping that does not rely on a QApplication
* being present.
*/
void bootstrap(const QString& uiLanguage)
{
#ifdef QT_NO_DEBUG
disableCoreDumps();
#endif
setupSearchPaths();
applyEarlyQNetworkAccessManagerWorkaround();
Translator::installTranslators(uiLanguage);
}
// LCOV_EXCL_START
void disableCoreDumps()
{
// default to true
// there is no point in printing a warning if this is not implemented on the platform
bool success = true;
#if defined(HAVE_RLIMIT_CORE)
struct rlimit limit;
limit.rlim_cur = 0;
limit.rlim_max = 0;
success = success && (setrlimit(RLIMIT_CORE, &limit) == 0);
#endif
// NOTE: Dumps cannot be disabled for snap builds as it prevents desktop portals from working
// See https://github.com/keepassxreboot/keepassxc/issues/7607#issuecomment-1109005206
#if defined(HAVE_PR_SET_DUMPABLE) && !defined(KEEPASSXC_DIST_SNAP)
success = success && (prctl(PR_SET_DUMPABLE, 0) == 0);
#endif
// Mac OS X
#ifdef HAVE_PT_DENY_ATTACH
success = success && (ptrace(PT_DENY_ATTACH, 0, 0, 0) == 0);
#endif
#ifdef Q_OS_WIN
success = success && createWindowsDACL();
#endif
if (!success) {
qWarning("Unable to disable core dumps.");
}
}
//
// This function grants the user associated with the process token minimal access rights and
// denies everything else on Windows. This includes PROCESS_QUERY_INFORMATION and
// PROCESS_VM_READ access rights that are required for MiniDumpWriteDump() or ReadProcessMemory().
// We do this using a discretionary access control list (DACL). Effectively this prevents
// crash dumps and disallows other processes from accessing our memory. This works as long
// as you do not have admin privileges, since then you are able to grant yourself the
// SeDebugPrivilege or SeTakeOwnershipPrivilege and circumvent the DACL.
//
bool createWindowsDACL()
{
bool bSuccess = false;
#ifdef Q_OS_WIN
// Process token and user
HANDLE hToken = nullptr;
PTOKEN_USER pTokenUser = nullptr;
DWORD cbBufferSize = 0;
PSID pLocalSystemSid = nullptr;
DWORD pLocalSystemSidSize = SECURITY_MAX_SID_SIZE;
PSID pOwnerRightsSid = nullptr;
DWORD pOwnerRightsSidSize = SECURITY_MAX_SID_SIZE;
// Access control list
PACL pACL = nullptr;
DWORD cbACL = 0;
// Open the access token associated with the calling process
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
goto Cleanup;
}
// Retrieve the token information in a TOKEN_USER structure
GetTokenInformation(hToken, TokenUser, nullptr, 0, &cbBufferSize);
pTokenUser = static_cast<PTOKEN_USER>(HeapAlloc(GetProcessHeap(), 0, cbBufferSize));
if (pTokenUser == nullptr) {
goto Cleanup;
}
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, cbBufferSize, &cbBufferSize)) {
goto Cleanup;
}
if (!IsValidSid(pTokenUser->User.Sid)) {
goto Cleanup;
}
// Retrieve LocalSystem account SID
pLocalSystemSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pLocalSystemSidSize));
if (pLocalSystemSid == nullptr) {
goto Cleanup;
}
if (!CreateWellKnownSid(WinLocalSystemSid, nullptr, pLocalSystemSid, &pLocalSystemSidSize)) {
goto Cleanup;
}
// Retrieve CreatorOwnerRights SID
pOwnerRightsSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pOwnerRightsSidSize));
if (pOwnerRightsSid == nullptr) {
goto Cleanup;
}
if (!CreateWellKnownSid(WinCreatorOwnerRightsSid, nullptr, pOwnerRightsSid, &pOwnerRightsSidSize)) {
auto error = GetLastError();
goto Cleanup;
}
// Calculate the amount of memory that must be allocated for the DACL
cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid)
+ sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pLocalSystemSid) + sizeof(ACCESS_ALLOWED_ACE)
+ GetLengthSid(pOwnerRightsSid);
// Create and initialize an ACL
pACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(), 0, cbACL));
if (pACL == nullptr) {
goto Cleanup;
}
if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
goto Cleanup;
}
// Add allowed access control entries, everything else is denied
if (!AddAccessAllowedAce(
pACL,
ACL_REVISION,
SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, // same as protected process
pTokenUser->User.Sid // pointer to the trustee's SID
)) {
goto Cleanup;
}
// Explicitly set "Process Owner" rights to Read Only. The default is Full Control.
if (!AddAccessAllowedAce(pACL, ACL_REVISION, READ_CONTROL, pOwnerRightsSid)) {
goto Cleanup;
}
#ifdef WITH_XC_SSHAGENT
// OpenSSH for Windows ssh-agent service is running as LocalSystem
if (!AddAccessAllowedAce(pACL,
ACL_REVISION,
PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, // just enough for ssh-agent
pLocalSystemSid // known LocalSystem sid
)) {
goto Cleanup;
}
#endif
// Set discretionary access control list
bSuccess = ERROR_SUCCESS
== SetSecurityInfo(GetCurrentProcess(), // object handle
SE_KERNEL_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the objects DACL
nullptr,
nullptr, // do not change owner or group
pACL, // DACL specified
nullptr // do not change SACL
);
Cleanup:
if (pACL) {
HeapFree(GetProcessHeap(), 0, pACL);
}
if (pLocalSystemSid) {
HeapFree(GetProcessHeap(), 0, pLocalSystemSid);
}
if (pOwnerRightsSid) {
HeapFree(GetProcessHeap(), 0, pOwnerRightsSid);
}
if (pTokenUser) {
HeapFree(GetProcessHeap(), 0, pTokenUser);
}
if (hToken) {
CloseHandle(hToken);
}
#endif
return bSuccess;
}
// LCOV_EXCL_STOP
void setupSearchPaths()
{
#ifdef Q_OS_WIN
// Make sure Windows doesn't load DLLs from the current working directory
SetDllDirectoryA("");
SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
#endif
}
} // namespace Bootstrap