VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/* $Id: SUPR3HardenedNoCrt-win.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Hardened main(), windows bits.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/nt/nt-and-windows.h>
42#include <AccCtrl.h>
43#include <AclApi.h>
44#ifndef PROCESS_SET_LIMITED_INFORMATION
45# define PROCESS_SET_LIMITED_INFORMATION 0x2000
46#endif
47
48#include <VBox/sup.h>
49#include <iprt/errcore.h>
50#include <iprt/assert.h>
51#include <iprt/ctype.h>
52#include <iprt/heap.h>
53#include <iprt/string.h>
54#include <iprt/initterm.h>
55#include <iprt/param.h>
56#include <iprt/path.h>
57#include <iprt/mem.h>
58#include <iprt/utf16.h>
59
60#include "SUPLibInternal.h"
61#include "win/SUPHardenedVerify-win.h"
62
63
64/*
65 * assert.cpp
66 */
67
68RTDATADECL(char) g_szRTAssertMsg1[1024];
69RTDATADECL(char) g_szRTAssertMsg2[4096];
70RTDATADECL(const char * volatile) g_pszRTAssertExpr;
71RTDATADECL(const char * volatile) g_pszRTAssertFile;
72RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
73RTDATADECL(const char * volatile) g_pszRTAssertFunction;
74
75
76RTDECL(bool) RTAssertMayPanic(void)
77{
78 return true;
79}
80
81
82RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
83{
84 /*
85 * Fill in the globals.
86 */
87 g_pszRTAssertExpr = pszExpr;
88 g_pszRTAssertFile = pszFile;
89 g_pszRTAssertFunction = pszFunction;
90 g_u32RTAssertLine = uLine;
91 RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
92 "\n!!Assertion Failed!!\n"
93 "Expression: %s\n"
94 "Location : %s(%d) %s\n",
95 pszExpr, pszFile, uLine, pszFunction);
96}
97
98
99RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
100{
101 RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, va);
102 if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN)
103 supR3HardenedFatalMsg(g_pszRTAssertExpr, kSupInitOp_Misc, VERR_INTERNAL_ERROR,
104 "%s%s", g_szRTAssertMsg1, g_szRTAssertMsg2);
105 else
106 supR3HardenedError(VERR_INTERNAL_ERROR, false/*fFatal*/, "%s%s", g_szRTAssertMsg1, g_szRTAssertMsg2);
107}
108
109
110/*
111 * Memory allocator.
112 */
113
114/** The handle of the heap we're using. */
115static HANDLE g_hSupR3HardenedHeap = NULL;
116/** Number of heaps used during early process init. */
117static uint32_t g_cSupR3HardenedEarlyHeaps = 0;
118/** Early process init heaps. */
119static struct
120{
121 /** The heap handle. */
122 RTHEAPSIMPLE hHeap;
123 /** The heap block pointer. */
124 void *pvBlock;
125 /** The size of the heap block. */
126 size_t cbBlock;
127 /** Number of active allocations on this heap. */
128 size_t cAllocations;
129} g_aSupR3HardenedEarlyHeaps[8];
130
131
132static uint32_t supR3HardenedEarlyFind(void *pv) RT_NOTHROW_DEF
133{
134 uint32_t iHeap = g_cSupR3HardenedEarlyHeaps;
135 while (iHeap-- > 0)
136 if ((uintptr_t)pv - (uintptr_t)g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock < g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock)
137 return iHeap;
138 return UINT32_MAX;
139}
140
141
142static void supR3HardenedEarlyCompact(void) RT_NOTHROW_DEF
143{
144 uint32_t iHeap = g_cSupR3HardenedEarlyHeaps;
145 while (iHeap-- > 0)
146 if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations == 0)
147 {
148 PVOID pvMem = g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock;
149 SIZE_T cbMem = g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock;
150 if (iHeap + 1 < g_cSupR3HardenedEarlyHeaps)
151 g_aSupR3HardenedEarlyHeaps[iHeap] = g_aSupR3HardenedEarlyHeaps[g_cSupR3HardenedEarlyHeaps - 1];
152 g_cSupR3HardenedEarlyHeaps--;
153
154 NTSTATUS rcNt = NtFreeVirtualMemory(NtCurrentProcess(), &pvMem, &cbMem, MEM_RELEASE);
155 Assert(NT_SUCCESS(rcNt)); RT_NOREF_PV(rcNt);
156 SUP_DPRINTF(("supR3HardenedEarlyCompact: Removed heap %#u (%#p LB %#zx)\n", iHeap, pvMem, cbMem));
157 }
158}
159
160
161static void *supR3HardenedEarlyAlloc(size_t cb, bool fZero) RT_NOTHROW_DEF
162{
163 /*
164 * Try allocate on existing heaps.
165 */
166 void *pv;
167 uint32_t iHeap = 0;
168 while (iHeap < g_cSupR3HardenedEarlyHeaps)
169 {
170 if (fZero)
171 pv = RTHeapSimpleAllocZ(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, cb, 0);
172 else
173 pv = RTHeapSimpleAlloc(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, cb, 0);
174 if (pv)
175 {
176 g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations++;
177#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
178 SUP_DPRINTF(("Early heap: %p LB %#zx - alloc\n", pv, cb));
179#endif
180 return pv;
181 }
182 iHeap++;
183 }
184
185 /*
186 * Add another heap.
187 */
188 if (iHeap == RT_ELEMENTS(g_aSupR3HardenedEarlyHeaps))
189 supR3HardenedFatal("Early heap table is full (cb=%#zx).\n", cb);
190 SIZE_T cbBlock = iHeap == 0 ? _1M : g_aSupR3HardenedEarlyHeaps[iHeap - 1].cbBlock * 2;
191 while (cbBlock <= cb * 2)
192 cbBlock *= 2;
193
194 PVOID pvBlock = NULL;
195 NTSTATUS rcNt = NtAllocateVirtualMemory(NtCurrentProcess(), &pvBlock, 0 /*ZeroBits*/, &cbBlock, MEM_COMMIT, PAGE_READWRITE);
196 if (!NT_SUCCESS(rcNt))
197 supR3HardenedFatal("NtAllocateVirtualMemory(,,,%#zx,,) failed: rcNt=%#x\n", cbBlock, rcNt);
198 SUP_DPRINTF(("New simple heap: #%u %p LB %#zx (for %zu allocation)\n", iHeap, pvBlock, cbBlock, cb));
199
200 RTHEAPSIMPLE hHeap;
201 int rc = RTHeapSimpleInit(&hHeap, pvBlock, cbBlock);
202 if (RT_FAILURE(rc))
203 supR3HardenedFatal("RTHeapSimpleInit(,%p,%#zx) failed: rc=%#x\n", pvBlock, cbBlock, rc);
204
205 if (fZero)
206 pv = RTHeapSimpleAllocZ(hHeap, cb, 0);
207 else
208 pv = RTHeapSimpleAlloc(hHeap, cb, 0);
209 if (!pv)
210 supR3HardenedFatal("RTHeapSimpleAlloc[Z] failed allocating %#zx bytes on a %#zu heap.\n", cb, cbBlock);
211
212 g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock = pvBlock;
213 g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock = cbBlock;
214 g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations = 1;
215 g_aSupR3HardenedEarlyHeaps[iHeap].hHeap = hHeap;
216
217 Assert(g_cSupR3HardenedEarlyHeaps == iHeap);
218 g_cSupR3HardenedEarlyHeaps = iHeap + 1;
219
220#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
221 SUP_DPRINTF(("Early heap: %p LB %#zx - alloc\n", pv, cb));
222#endif
223 return pv;
224}
225
226
227/**
228 * Lazy heap initialization function.
229 *
230 * @returns Heap handle.
231 */
232static HANDLE supR3HardenedHeapInit(void) RT_NOTHROW_DEF
233{
234 Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED);
235 HANDLE hHeap = RtlCreateHeap(HEAP_GROWABLE | HEAP_CLASS_PRIVATE, NULL /*HeapBase*/,
236 0 /*ReserveSize*/, 0 /*CommitSize*/, NULL /*Lock*/, NULL /*Parameters*/);
237 if (hHeap)
238 {
239 g_hSupR3HardenedHeap = hHeap;
240 return hHeap;
241 }
242
243 supR3HardenedFatal("RtlCreateHeap failed.\n");
244 /* not reached */
245}
246
247
248/**
249 * Compacts the heaps before enter wait for parent/child.
250 */
251DECLHIDDEN(void) supR3HardenedWinCompactHeaps(void)
252{
253 if (g_hSupR3HardenedHeap)
254 RtlCompactHeap(g_hSupR3HardenedHeap, 0 /*dwFlags*/);
255 RtlCompactHeap(GetProcessHeap(), 0 /*dwFlags*/);
256 supR3HardenedEarlyCompact();
257}
258
259
260
261#undef RTMemTmpAllocTag
262RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
263{
264 return RTMemAllocTag(cb, pszTag);
265}
266
267
268#undef RTMemTmpAllocZTag
269RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
270{
271 return RTMemAllocZTag(cb, pszTag);
272}
273
274
275#undef RTMemTmpFree
276RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW_DEF
277{
278 RTMemFree(pv);
279}
280
281
282#undef RTMemAllocTag
283RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
284{
285 RT_NOREF1(pszTag);
286 HANDLE hHeap = g_hSupR3HardenedHeap;
287 if (!hHeap)
288 {
289 if ( g_fSupEarlyProcessInit
290 && g_enmSupR3HardenedMainState <= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED)
291 return supR3HardenedEarlyAlloc(cb, false /*fZero*/);
292 hHeap = supR3HardenedHeapInit();
293 }
294
295 void *pv = RtlAllocateHeap(hHeap, 0 /*fFlags*/, cb);
296 if (!pv)
297 supR3HardenedFatal("RtlAllocateHeap failed to allocate %zu bytes.\n", cb);
298 return pv;
299}
300
301
302#undef RTMemAllocZTag
303RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
304{
305 RT_NOREF1(pszTag);
306 HANDLE hHeap = g_hSupR3HardenedHeap;
307 if (!hHeap)
308 {
309 if ( g_fSupEarlyProcessInit
310 && g_enmSupR3HardenedMainState <= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED)
311 return supR3HardenedEarlyAlloc(cb, true /*fZero*/);
312 hHeap = supR3HardenedHeapInit();
313 }
314
315 void *pv = RtlAllocateHeap(hHeap, HEAP_ZERO_MEMORY, cb);
316 if (!pv)
317 supR3HardenedFatal("RtlAllocateHeap failed to allocate %zu bytes.\n", cb);
318 return pv;
319}
320
321
322#undef RTMemAllocVarTag
323RTDECL(void *) RTMemAllocVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_DEF
324{
325 size_t cbAligned;
326 if (cbUnaligned >= 16)
327 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
328 else
329 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
330 return RTMemAllocTag(cbAligned, pszTag);
331}
332
333
334#undef RTMemAllocZVarTag
335RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_DEF
336{
337 size_t cbAligned;
338 if (cbUnaligned >= 16)
339 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
340 else
341 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
342 return RTMemAllocZTag(cbAligned, pszTag);
343}
344
345
346#undef RTMemReallocTag
347RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
348{
349 if (!pvOld)
350 return RTMemAllocZTag(cbNew, pszTag);
351
352 void *pv;
353 if (g_fSupEarlyProcessInit)
354 {
355 uint32_t iHeap = supR3HardenedEarlyFind(pvOld);
356 if (iHeap != UINT32_MAX)
357 {
358#if 0 /* RTHeapSimpleRealloc is not implemented */
359 /* If this is before we can use a regular heap, we try resize
360 within the simple heap. (There are a lot of array growing in
361 the ASN.1 code.) */
362 if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
363 {
364 pv = RTHeapSimpleRealloc(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld, cbNew, 0);
365 if (pv)
366 {
367# ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
368 SUP_DPRINTF(("Early heap: %p LB %#zx, was %p - realloc\n", pvNew, cbNew, pvOld));
369# endif
370 return pv;
371 }
372 }
373#endif
374
375 /* Either we can't reallocate it on the same simple heap, or we're
376 past hardened main and wish to migrate everything over on the
377 real heap. */
378 size_t cbOld = RTHeapSimpleSize(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld);
379 pv = RTMemAllocTag(cbNew, pszTag);
380 if (pv)
381 {
382 memcpy(pv, pvOld, RT_MIN(cbOld, cbNew));
383 RTHeapSimpleFree(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld);
384 if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations)
385 g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations--;
386 if ( !g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations
387 && g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
388 supR3HardenedEarlyCompact();
389 }
390# ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
391 SUP_DPRINTF(("Early heap: %p LB %#zx, was %p %LB %#zx - realloc\n", pv, cbNew, pvOld, cbOld));
392# endif
393 return pv;
394 }
395 Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED);
396 }
397
398 /* Allocate from the regular heap. */
399 HANDLE hHeap = g_hSupR3HardenedHeap;
400 Assert(hHeap != NULL);
401 pv = RtlReAllocateHeap(hHeap, 0 /*dwFlags*/, pvOld, cbNew);
402 if (!pv)
403 supR3HardenedFatal("RtlReAllocateHeap failed to allocate %zu bytes.\n", cbNew);
404 return pv;
405}
406
407
408#undef RTMemFree
409RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_DEF
410{
411 if (pv)
412 {
413 if (g_fSupEarlyProcessInit)
414 {
415 uint32_t iHeap = supR3HardenedEarlyFind(pv);
416 if (iHeap != UINT32_MAX)
417 {
418#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
419 SUP_DPRINTF(("Early heap: %p - free\n", pv));
420#endif
421 RTHeapSimpleFree(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pv);
422 if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations)
423 g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations--;
424 if ( !g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations
425 && g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
426 supR3HardenedEarlyCompact();
427 return;
428 }
429 Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED);
430 }
431
432 HANDLE hHeap = g_hSupR3HardenedHeap;
433 Assert(hHeap != NULL);
434 RtlFreeHeap(hHeap, 0 /* dwFlags*/, pv);
435 }
436}
437
438
439/*
440 * Simplified version of RTMemWipeThoroughly that avoids dragging in the
441 * random number code.
442 */
443
444RTDECL(void) RTMemWipeThoroughly(void *pv, size_t cb, size_t cMinPasses) RT_NO_THROW_DEF
445{
446 size_t cPasses = RT_MIN(cMinPasses, 6);
447 static const uint32_t s_aPatterns[] = { 0x00, 0xaa, 0x55, 0xff, 0xf0, 0x0f, 0xcc, 0x3c, 0xc3 };
448 uint32_t iPattern = 0;
449 do
450 {
451 memset(pv, s_aPatterns[iPattern], cb);
452 iPattern = (iPattern + 1) % RT_ELEMENTS(s_aPatterns);
453 ASMMemoryFence();
454
455 memset(pv, s_aPatterns[iPattern], cb);
456 iPattern = (iPattern + 1) % RT_ELEMENTS(s_aPatterns);
457 ASMMemoryFence();
458
459 memset(pv, s_aPatterns[iPattern], cb);
460 iPattern = (iPattern + 1) % RT_ELEMENTS(s_aPatterns);
461 ASMMemoryFence();
462 } while (cPasses-- > 0);
463
464 memset(pv, 0xff, cb);
465 ASMMemoryFence();
466}
467
468
469
470/*
471 * path-win.cpp
472 */
473
474RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cbPath)
475{
476 int rc;
477 if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
478/** @todo Rainy day: improve this by checking the process parameter block
479 * (needs to be normalized). */
480 rc = RTStrCopy(pszPath, cbPath, "C:\\");
481 else
482 {
483 /*
484 * GetCurrentDirectory may in some cases omit the drive letter, according
485 * to MSDN, thus the GetFullPathName call.
486 */
487 RTUTF16 wszCurPath[RTPATH_MAX];
488 if (GetCurrentDirectoryW(RTPATH_MAX, wszCurPath))
489 {
490 RTUTF16 wszFullPath[RTPATH_MAX];
491 if (GetFullPathNameW(wszCurPath, RTPATH_MAX, wszFullPath, NULL))
492 rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
493 else
494 rc = RTErrConvertFromWin32(RtlGetLastWin32Error());
495 }
496 else
497 rc = RTErrConvertFromWin32(RtlGetLastWin32Error());
498 }
499 return rc;
500}
501
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette