VirtualBox

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

Last change on this file since 86719 was 85127, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Made DECLHIDDEN imply nothrow and restrict its use to function (just like the newly added DECL_HIDDEN_NOTHROW). Added DECL_HIDDEN_ONLY and DECL_HIDDEN_THROW to accompany it. bugref:9794

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