keepassxc

Форк
0
/
Bootstrap.cpp 
264 строки · 8.8 Кб
1
/*
2
 *  Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
3
 *
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.
8
 *
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.
13
 *
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/>.
16
 */
17

18
#include "Bootstrap.h"
19
#include "config-keepassx.h"
20
#include "core/Translator.h"
21

22
#ifdef Q_OS_WIN
23
#include <aclapi.h> // for createWindowsDACL()
24
#include <windows.h> // for Sleep(), SetDllDirectoryA(), SetSearchPathMode(), ...
25
#undef MessageBox
26
#endif
27

28
#if defined(HAVE_RLIMIT_CORE)
29
#include <sys/resource.h>
30
#endif
31

32
#if defined(HAVE_PR_SET_DUMPABLE)
33
#include <sys/prctl.h>
34
#endif
35

36
#ifdef HAVE_PT_DENY_ATTACH
37
// clang-format off
38
#include <sys/types.h>
39
#include <sys/ptrace.h>
40
// clang-format on
41
#endif
42

43
namespace Bootstrap
44
{
45
    /**
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
53
     * For more info see:
54
     * - https://bugreports.qt.io/browse/QTBUG-40332
55
     * - https://bugreports.qt.io/browse/QTBUG-46015
56
     */
57
    static inline void applyEarlyQNetworkAccessManagerWorkaround()
58
    {
59
        qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
60
    }
61

62
    /**
63
     * Perform early application bootstrapping that does not rely on a QApplication
64
     * being present.
65
     */
66
    void bootstrap(const QString& uiLanguage)
67
    {
68
#ifdef QT_NO_DEBUG
69
        disableCoreDumps();
70
#endif
71

72
        setupSearchPaths();
73
        applyEarlyQNetworkAccessManagerWorkaround();
74

75
        Translator::installTranslators(uiLanguage);
76
    }
77

78
    // LCOV_EXCL_START
79
    void disableCoreDumps()
80
    {
81
        // default to true
82
        // there is no point in printing a warning if this is not implemented on the platform
83
        bool success = true;
84

85
#if defined(HAVE_RLIMIT_CORE)
86
        struct rlimit limit;
87
        limit.rlim_cur = 0;
88
        limit.rlim_max = 0;
89
        success = success && (setrlimit(RLIMIT_CORE, &limit) == 0);
90
#endif
91

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);
96
#endif
97

98
// Mac OS X
99
#ifdef HAVE_PT_DENY_ATTACH
100
        success = success && (ptrace(PT_DENY_ATTACH, 0, 0, 0) == 0);
101
#endif
102

103
#ifdef Q_OS_WIN
104
        success = success && createWindowsDACL();
105
#endif
106

107
        if (!success) {
108
            qWarning("Unable to disable core dumps.");
109
        }
110
    }
111

112
    //
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.
120
    //
121
    bool createWindowsDACL()
122
    {
123
        bool bSuccess = false;
124

125
#ifdef Q_OS_WIN
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;
134

135
        // Access control list
136
        PACL pACL = nullptr;
137
        DWORD cbACL = 0;
138

139
        // Open the access token associated with the calling process
140
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
141
            goto Cleanup;
142
        }
143

144
        // Retrieve the token information in a TOKEN_USER structure
145
        GetTokenInformation(hToken, TokenUser, nullptr, 0, &cbBufferSize);
146

147
        pTokenUser = static_cast<PTOKEN_USER>(HeapAlloc(GetProcessHeap(), 0, cbBufferSize));
148
        if (pTokenUser == nullptr) {
149
            goto Cleanup;
150
        }
151

152
        if (!GetTokenInformation(hToken, TokenUser, pTokenUser, cbBufferSize, &cbBufferSize)) {
153
            goto Cleanup;
154
        }
155

156
        if (!IsValidSid(pTokenUser->User.Sid)) {
157
            goto Cleanup;
158
        }
159

160
        // Retrieve LocalSystem account SID
161
        pLocalSystemSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pLocalSystemSidSize));
162
        if (pLocalSystemSid == nullptr) {
163
            goto Cleanup;
164
        }
165

166
        if (!CreateWellKnownSid(WinLocalSystemSid, nullptr, pLocalSystemSid, &pLocalSystemSidSize)) {
167
            goto Cleanup;
168
        }
169

170
        // Retrieve CreaterOwnerRights SID
171
        pOwnerRightsSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pOwnerRightsSidSize));
172
        if (pOwnerRightsSid == nullptr) {
173
            goto Cleanup;
174
        }
175

176
        if (!CreateWellKnownSid(WinCreatorOwnerRightsSid, nullptr, pOwnerRightsSid, &pOwnerRightsSidSize)) {
177
            auto error = GetLastError();
178
            goto Cleanup;
179
        }
180

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);
184

185
        // Create and initialize an ACL
186
        pACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(), 0, cbACL));
187
        if (pACL == nullptr) {
188
            goto Cleanup;
189
        }
190

191
        if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
192
            goto Cleanup;
193
        }
194

195
        // Add allowed access control entries, everything else is denied
196
        if (!AddAccessAllowedAce(
197
                pACL,
198
                ACL_REVISION,
199
                SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, // same as protected process
200
                pTokenUser->User.Sid // pointer to the trustee's SID
201
                )) {
202
            goto Cleanup;
203
        }
204

205
        // Explicitly set "Process Owner" rights to Read Only. The default is Full Control.
206
        if (!AddAccessAllowedAce(pACL, ACL_REVISION, READ_CONTROL, pOwnerRightsSid)) {
207
            goto Cleanup;
208
        }
209

210
#ifdef WITH_XC_SSHAGENT
211
        // OpenSSH for Windows ssh-agent service is running as LocalSystem
212
        if (!AddAccessAllowedAce(pACL,
213
                                 ACL_REVISION,
214
                                 PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, // just enough for ssh-agent
215
                                 pLocalSystemSid // known LocalSystem sid
216
                                 )) {
217
            goto Cleanup;
218
        }
219
#endif
220

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
226
                                      nullptr,
227
                                      nullptr, // do not change owner or group
228
                                      pACL, // DACL specified
229
                                      nullptr // do not change SACL
230
                   );
231

232
    Cleanup:
233

234
        if (pACL) {
235
            HeapFree(GetProcessHeap(), 0, pACL);
236
        }
237
        if (pLocalSystemSid) {
238
            HeapFree(GetProcessHeap(), 0, pLocalSystemSid);
239
        }
240
        if (pOwnerRightsSid) {
241
            HeapFree(GetProcessHeap(), 0, pOwnerRightsSid);
242
        }
243
        if (pTokenUser) {
244
            HeapFree(GetProcessHeap(), 0, pTokenUser);
245
        }
246
        if (hToken) {
247
            CloseHandle(hToken);
248
        }
249
#endif
250

251
        return bSuccess;
252
    }
253
    // LCOV_EXCL_STOP
254

255
    void setupSearchPaths()
256
    {
257
#ifdef Q_OS_WIN
258
        // Make sure Windows doesn't load DLLs from the current working directory
259
        SetDllDirectoryA("");
260
        SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
261
#endif
262
    }
263

264
} // namespace Bootstrap
265

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.