VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPLibLdr.cpp@ 93239

Last change on this file since 93239 was 93239, checked in by vboxsync, 2 years ago

SUP,Installer/win: Renamed VBoxDrv.sys to VBoxSup.sys. bugref:10162

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.9 KB
Line 
1/* $Id: SUPLibLdr.cpp 93239 2022-01-14 19:15:41Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Loader related bits.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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#define LOG_GROUP LOG_GROUP_SUP
32#include <VBox/sup.h>
33#include <VBox/err.h>
34#include <VBox/param.h>
35#include <VBox/log.h>
36#include <VBox/VBoxTpG.h>
37
38#include <iprt/assert.h>
39#include <iprt/alloc.h>
40#include <iprt/alloca.h>
41#include <iprt/ldr.h>
42#include <iprt/asm.h>
43#include <iprt/mp.h>
44#include <iprt/cpuset.h>
45#include <iprt/thread.h>
46#include <iprt/process.h>
47#include <iprt/path.h>
48#include <iprt/string.h>
49#include <iprt/env.h>
50#include <iprt/rand.h>
51#include <iprt/x86.h>
52
53#include "SUPDrvIOC.h"
54#include "SUPLibInternal.h"
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60/** R0 VMM module name. */
61#define VMMR0_NAME "VMMR0"
62
63
64/*********************************************************************************************************************************
65* Structures and Typedefs *
66*********************************************************************************************************************************/
67typedef DECLCALLBACKTYPE(int, FNCALLVMMR0,(PVMR0 pVMR0, unsigned uOperation, void *pvArg));
68typedef FNCALLVMMR0 *PFNCALLVMMR0;
69
70
71/*********************************************************************************************************************************
72* Global Variables *
73*********************************************************************************************************************************/
74/** VMMR0 Load Address. */
75static RTR0PTR g_pvVMMR0 = NIL_RTR0PTR;
76
77
78/*********************************************************************************************************************************
79* Internal Functions *
80*********************************************************************************************************************************/
81static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler,
82 PRTERRINFO pErrInfo, void **ppvImageBase);
83static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
84 unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
85
86
87SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo)
88{
89 /*
90 * Check that the module can be trusted.
91 */
92 int rc = SUPR3HardenedVerifyPlugIn(pszFilename, pErrInfo);
93 if (RT_SUCCESS(rc))
94 {
95 rc = supLoadModule(pszFilename, pszModule, NULL, pErrInfo, ppvImageBase);
96 if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
97 RTErrInfoSetF(pErrInfo, rc, "SUPR3LoadModule: supLoadModule returned %Rrc", rc);
98 }
99 return rc;
100}
101
102
103SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule,
104 const char *pszSrvReqHandler, void **ppvImageBase)
105{
106 AssertPtrReturn(pszSrvReqHandler, VERR_INVALID_PARAMETER);
107
108 /*
109 * Check that the module can be trusted.
110 */
111 int rc = SUPR3HardenedVerifyPlugIn(pszFilename, NULL /*pErrInfo*/);
112 if (RT_SUCCESS(rc))
113 rc = supLoadModule(pszFilename, pszModule, pszSrvReqHandler, NULL /*pErrInfo*/, ppvImageBase);
114 else
115 LogRel(("SUPR3LoadServiceModule: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
116 return rc;
117}
118
119
120/**
121 * Argument package for supLoadModuleResolveImport.
122 */
123typedef struct SUPLDRRESIMPARGS
124{
125 const char *pszModule;
126 PRTERRINFO pErrInfo;
127 uint32_t fLoadReq; /**< SUPLDRLOAD_F_XXX */
128} SUPLDRRESIMPARGS, *PSUPLDRRESIMPARGS;
129
130/**
131 * Resolve an external symbol during RTLdrGetBits().
132 *
133 * @returns VBox status code.
134 * @param hLdrMod The loader module handle.
135 * @param pszModule Module name.
136 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
137 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
138 * @param pValue Where to store the symbol value (address).
139 * @param pvUser User argument.
140 */
141static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
142 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
143{
144 NOREF(hLdrMod); NOREF(uSymbol);
145 AssertPtr(pValue);
146 AssertPtr(pvUser);
147 PSUPLDRRESIMPARGS pArgs = (PSUPLDRRESIMPARGS)pvUser;
148
149 /*
150 * Only SUPR0 and VMMR0.r0
151 */
152 if ( pszModule
153 && *pszModule
154 && strcmp(pszModule, "VBoxSup.sys")
155 && strcmp(pszModule, "VBoxDrv.sys") /* old name */
156 && strcmp(pszModule, "VMMR0.r0"))
157 {
158#if defined(RT_OS_WINDOWS) && 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrv-win.cpp */
159 if (strcmp(pszModule, "ntoskrnl.exe") == 0)
160 {
161 *pValue = 42; /* Non-zero so ring-0 can find the end of the IAT and exclude it when comparing. */
162 return VINF_SUCCESS;
163 }
164#endif
165 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pArgs->pszModule, pszModule));
166 return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
167 "Unexpected import module '%s' in '%s'", pszModule, pArgs->pszModule);
168 }
169
170 /*
171 * No ordinals.
172 */
173 if (uSymbol != ~0U)
174 {
175 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pArgs->pszModule, uSymbol));
176 return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
177 "Unexpected ordinal import (%#x) in '%s'", uSymbol, pArgs->pszModule);
178 }
179
180 /*
181 * Lookup symbol.
182 */
183 /* Skip the 64-bit ELF import prefix first. */
184 /** @todo is this actually used??? */
185 if (!strncmp(pszSymbol, RT_STR_TUPLE("SUPR0$")))
186 pszSymbol += sizeof("SUPR0$") - 1;
187
188 /*
189 * Check the VMMR0.r0 module if loaded.
190 */
191 if (g_pvVMMR0 != NIL_RTR0PTR)
192 {
193 void *pvValue;
194 if (!SUPR3GetSymbolR0((void *)g_pvVMMR0, pszSymbol, &pvValue))
195 {
196 *pValue = (uintptr_t)pvValue;
197 pArgs->fLoadReq |= SUPLDRLOAD_F_DEP_VMMR0;
198 return VINF_SUCCESS;
199 }
200 }
201
202 /* iterate the function table. */
203 int c = g_pSupFunctions->u.Out.cFunctions;
204 PSUPFUNC pFunc = &g_pSupFunctions->u.Out.aFunctions[0];
205 while (c-- > 0)
206 {
207 if (!strcmp(pFunc->szName, pszSymbol))
208 {
209 *pValue = (uintptr_t)pFunc->pfn;
210 return VINF_SUCCESS;
211 }
212 pFunc++;
213 }
214
215 /*
216 * The GIP.
217 */
218 if ( pszSymbol
219 && g_pSUPGlobalInfoPage
220 && g_pSUPGlobalInfoPageR0
221 && !strcmp(pszSymbol, "g_SUPGlobalInfoPage")
222 )
223 {
224 *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
225 return VINF_SUCCESS;
226 }
227
228 /*
229 * Symbols that are undefined by convention.
230 */
231#ifdef RT_OS_SOLARIS
232 static const char * const s_apszConvSyms[] =
233 {
234 "", "mod_getctl",
235 "", "mod_install",
236 "", "mod_remove",
237 "", "mod_info",
238 "", "mod_miscops",
239 };
240 for (unsigned i = 0; i < RT_ELEMENTS(s_apszConvSyms); i += 2)
241 {
242 if ( !RTStrCmp(s_apszConvSyms[i], pszModule)
243 && !RTStrCmp(s_apszConvSyms[i + 1], pszSymbol))
244 {
245 *pValue = ~(uintptr_t)0;
246 return VINF_SUCCESS;
247 }
248 }
249#endif
250
251 /*
252 * Despair.
253 */
254 c = g_pSupFunctions->u.Out.cFunctions;
255 pFunc = &g_pSupFunctions->u.Out.aFunctions[0];
256 while (c-- > 0)
257 {
258 RTAssertMsg2Weak("%d: %s\n", g_pSupFunctions->u.Out.cFunctions - c, pFunc->szName);
259 pFunc++;
260 }
261 RTAssertMsg2Weak("%s is importing %s which we couldn't find\n", pArgs->pszModule, pszSymbol);
262
263 AssertLogRelMsgFailed(("%s is importing %s which we couldn't find\n", pArgs->pszModule, pszSymbol));
264 if (g_uSupFakeMode)
265 {
266 *pValue = 0xdeadbeef;
267 return VINF_SUCCESS;
268 }
269 return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
270 "Unable to locate imported symbol '%s%s%s' for module '%s'",
271 pszModule ? pszModule : "",
272 pszModule && *pszModule ? "." : "",
273 pszSymbol,
274 pArgs->pszModule);
275}
276
277
278/** Argument package for supLoadModuleCalcSizeCB. */
279typedef struct SUPLDRCALCSIZEARGS
280{
281 size_t cbStrings;
282 uint32_t cSymbols;
283 size_t cbImage;
284} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
285
286/**
287 * Callback used to calculate the image size.
288 * @return VINF_SUCCESS
289 */
290static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
291{
292 PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
293 if ( pszSymbol != NULL
294 && *pszSymbol
295 && Value <= pArgs->cbImage)
296 {
297 pArgs->cSymbols++;
298 pArgs->cbStrings += strlen(pszSymbol) + 1;
299 }
300 NOREF(hLdrMod); NOREF(uSymbol);
301 return VINF_SUCCESS;
302}
303
304
305/** Argument package for supLoadModuleCreateTabsCB. */
306typedef struct SUPLDRCREATETABSARGS
307{
308 size_t cbImage;
309 PSUPLDRSYM pSym;
310 char *pszBase;
311 char *psz;
312} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
313
314/**
315 * Callback used to calculate the image size.
316 * @return VINF_SUCCESS
317 */
318static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
319{
320 PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
321 if ( pszSymbol != NULL
322 && *pszSymbol
323 && Value <= pArgs->cbImage)
324 {
325 pArgs->pSym->offSymbol = (uint32_t)Value;
326 pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
327 pArgs->pSym++;
328
329 size_t cbCopy = strlen(pszSymbol) + 1;
330 memcpy(pArgs->psz, pszSymbol, cbCopy);
331 pArgs->psz += cbCopy;
332 }
333 NOREF(hLdrMod); NOREF(uSymbol);
334 return VINF_SUCCESS;
335}
336
337
338/** Argument package for supLoadModuleCompileSegmentsCB. */
339typedef struct SUPLDRCOMPSEGTABARGS
340{
341 uint32_t uStartRva;
342 uint32_t uEndRva;
343 uint32_t fProt;
344 uint32_t iSegs;
345 uint32_t cSegsAlloc;
346 PSUPLDRSEG paSegs;
347 PRTERRINFO pErrInfo;
348} SUPLDRCOMPSEGTABARGS, *PSUPLDRCOMPSEGTABARGS;
349
350/**
351 * @callback_method_impl{FNRTLDRENUMSEGS,
352 * Compile list of segments with the same memory protection.}
353 */
354static DECLCALLBACK(int) supLoadModuleCompileSegmentsCB(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
355{
356 PSUPLDRCOMPSEGTABARGS pArgs = (PSUPLDRCOMPSEGTABARGS)pvUser;
357 AssertCompile(RTMEM_PROT_READ == SUPLDR_PROT_READ);
358 AssertCompile(RTMEM_PROT_WRITE == SUPLDR_PROT_WRITE);
359 AssertCompile(RTMEM_PROT_EXEC == SUPLDR_PROT_EXEC);
360 RT_NOREF(hLdrMod);
361
362 Log2(("supLoadModuleCompileSegmentsCB: %RTptr/%RTptr LB %RTptr/%RTptr prot %#x %s\n",
363 pSeg->LinkAddress, pSeg->RVA, pSeg->cbMapped, pSeg->cb, pSeg->fProt, pSeg->pszName));
364
365 /* Ignore segments not part of the loaded image. */
366 if (pSeg->RVA == NIL_RTLDRADDR || pSeg->cbMapped == 0)
367 {
368 Log2(("supLoadModuleCompileSegmentsCB: -> skipped\n"));
369 return VINF_SUCCESS;
370 }
371
372 /* We currently ASSUME that all relevant segments are in ascending RVA order. */
373 AssertReturn(pSeg->RVA >= pArgs->uEndRva,
374 RTERRINFO_LOG_REL_SET_F(pArgs->pErrInfo, VERR_BAD_EXE_FORMAT, "Out of order segment: %p LB %#zx #%.*s",
375 pSeg->RVA, pSeg->cb, pSeg->cchName, pSeg->pszName));
376
377 /* We ASSUME the cbMapped field is implemented. */
378 AssertReturn(pSeg->cbMapped != NIL_RTLDRADDR, VERR_INTERNAL_ERROR_2);
379 AssertReturn(pSeg->cbMapped < _1G, VERR_INTERNAL_ERROR_4);
380 uint32_t cbMapped = (uint32_t)pSeg->cbMapped;
381 AssertReturn(pSeg->RVA < _1G, VERR_INTERNAL_ERROR_3);
382 uint32_t uRvaSeg = (uint32_t)pSeg->RVA;
383
384 /*
385 * If the protection is the same as the previous segment,
386 * just update uEndRva and continue.
387 */
388 uint32_t fProt = pSeg->fProt;
389#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
390 if (fProt & RTMEM_PROT_EXEC)
391 fProt |= fProt & RTMEM_PROT_READ;
392#endif
393 if (pSeg->fProt == pArgs->fProt)
394 {
395 pArgs->uEndRva = uRvaSeg + cbMapped;
396 Log2(("supLoadModuleCompileSegmentsCB: -> merged, end %#x\n", pArgs->uEndRva));
397 return VINF_SUCCESS;
398 }
399
400 /*
401 * The protection differs, so commit current segment and start a new one.
402 * However, if the new segment and old segment share a page, this becomes
403 * a little more complicated...
404 */
405 if (pArgs->uStartRva < pArgs->uEndRva)
406 {
407 if (((pArgs->uEndRva - 1) >> PAGE_SHIFT) != (uRvaSeg >> PAGE_SHIFT))
408 {
409 /* No common page, so make the new segment start on a page boundrary. */
410 cbMapped += uRvaSeg & PAGE_OFFSET_MASK;
411 uRvaSeg &= ~(uint32_t)PAGE_OFFSET_MASK;
412 Assert(pArgs->uEndRva <= uRvaSeg);
413 Log2(("supLoadModuleCompileSegmentsCB: -> new, no common\n"));
414 }
415 else if ((fProt & pArgs->fProt) == fProt)
416 {
417 /* The current segment includes the memory protections of the
418 previous, so include the common page in it: */
419 uint32_t const cbCommon = PAGE_SIZE - (uRvaSeg & PAGE_OFFSET_MASK);
420 if (cbCommon >= cbMapped)
421 {
422 pArgs->uEndRva = uRvaSeg + cbMapped;
423 Log2(("supLoadModuleCompileSegmentsCB: -> merge, %#x common, upgrading prot to %#x, end %#x\n",
424 cbCommon, pArgs->fProt, pArgs->uEndRva));
425 return VINF_SUCCESS; /* New segment was smaller than a page. */
426 }
427 cbMapped -= cbCommon;
428 uRvaSeg += cbCommon;
429 Assert(pArgs->uEndRva <= uRvaSeg);
430 Log2(("supLoadModuleCompileSegmentsCB: -> new, %#x common into previous\n", cbCommon));
431 }
432 else if ((fProt & pArgs->fProt) == pArgs->fProt)
433 {
434 /* The new segment includes the memory protections of the
435 previous, so include the common page in it: */
436 cbMapped += uRvaSeg & PAGE_OFFSET_MASK;
437 uRvaSeg &= ~(uint32_t)PAGE_OFFSET_MASK;
438 if (uRvaSeg == pArgs->uStartRva)
439 {
440 pArgs->fProt = fProt;
441 pArgs->uEndRva = uRvaSeg + cbMapped;
442 Log2(("supLoadModuleCompileSegmentsCB: -> upgrade current protection, end %#x\n", pArgs->uEndRva));
443 return VINF_SUCCESS; /* Current segment was smaller than a page. */
444 }
445 Log2(("supLoadModuleCompileSegmentsCB: -> new, %#x common into new\n", (uint32_t)(pSeg->RVA & PAGE_OFFSET_MASK)));
446 }
447 else
448 {
449 /* Create a new segment for the common page with the combined protection. */
450 Log2(("supLoadModuleCompileSegmentsCB: -> it's complicated...\n"));
451 pArgs->uEndRva &= ~(uint32_t)PAGE_OFFSET_MASK;
452 if (pArgs->uEndRva > pArgs->uStartRva)
453 {
454 Log2(("supLoadModuleCompileSegmentsCB: SUP Seg #%u: %#x LB %#x prot %#x\n",
455 pArgs->iSegs, pArgs->uStartRva, pArgs->uEndRva - pArgs->uStartRva, pArgs->fProt));
456 if (pArgs->paSegs)
457 {
458 AssertReturn(pArgs->iSegs < pArgs->cSegsAlloc, VERR_INTERNAL_ERROR_5);
459 pArgs->paSegs[pArgs->iSegs].off = pArgs->uStartRva;
460 pArgs->paSegs[pArgs->iSegs].cb = pArgs->uEndRva - pArgs->uStartRva;
461 pArgs->paSegs[pArgs->iSegs].fProt = pArgs->fProt;
462 pArgs->paSegs[pArgs->iSegs].fUnused = 0;
463 }
464 pArgs->iSegs++;
465 pArgs->uStartRva = pArgs->uEndRva;
466 }
467 pArgs->fProt |= fProt;
468
469 uint32_t const cbCommon = PAGE_SIZE - (uRvaSeg & PAGE_OFFSET_MASK);
470 if (cbCommon >= cbMapped)
471 {
472 fProt |= pArgs->fProt;
473 pArgs->uEndRva = uRvaSeg + cbMapped;
474 return VINF_SUCCESS; /* New segment was smaller than a page. */
475 }
476 cbMapped -= cbCommon;
477 uRvaSeg += cbCommon;
478 Assert(uRvaSeg - pArgs->uStartRva == PAGE_SIZE);
479 }
480
481 /* The current segment should end where the new one starts, no gaps. */
482 pArgs->uEndRva = uRvaSeg;
483
484 /* Emit the current segment */
485 Log2(("supLoadModuleCompileSegmentsCB: SUP Seg #%u: %#x LB %#x prot %#x\n",
486 pArgs->iSegs, pArgs->uStartRva, pArgs->uEndRva - pArgs->uStartRva, pArgs->fProt));
487 if (pArgs->paSegs)
488 {
489 AssertReturn(pArgs->iSegs < pArgs->cSegsAlloc, VERR_INTERNAL_ERROR_5);
490 pArgs->paSegs[pArgs->iSegs].off = pArgs->uStartRva;
491 pArgs->paSegs[pArgs->iSegs].cb = pArgs->uEndRva - pArgs->uStartRva;
492 pArgs->paSegs[pArgs->iSegs].fProt = pArgs->fProt;
493 pArgs->paSegs[pArgs->iSegs].fUnused = 0;
494 }
495 pArgs->iSegs++;
496 }
497 /* else: current segment is empty */
498
499 /* Start the new segment. */
500 Assert(!(uRvaSeg & PAGE_OFFSET_MASK));
501 pArgs->fProt = fProt;
502 pArgs->uStartRva = uRvaSeg;
503 pArgs->uEndRva = uRvaSeg + cbMapped;
504 return VINF_SUCCESS;
505}
506
507
508/**
509 * Worker for supLoadModule().
510 */
511static int supLoadModuleInner(RTLDRMOD hLdrMod, PSUPLDRLOAD pLoadReq, uint32_t cbImageWithEverything,
512 RTR0PTR uImageBase, size_t cbImage, const char *pszModule, const char *pszFilename,
513 bool fNativeLoader, bool fIsVMMR0, const char *pszSrvReqHandler,
514 uint32_t offSymTab, uint32_t cSymbols,
515 uint32_t offStrTab, size_t cbStrTab,
516 uint32_t offSegTab, uint32_t cSegments,
517 PRTERRINFO pErrInfo)
518{
519 /*
520 * Get the image bits.
521 */
522 SUPLDRRESIMPARGS Args = { pszModule, pErrInfo, 0 };
523 int rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase, supLoadModuleResolveImport, &Args);
524 if (RT_FAILURE(rc))
525 {
526 LogRel(("SUP: RTLdrGetBits failed for %s (%s). rc=%Rrc\n", pszModule, pszFilename, rc));
527 if (!RTErrInfoIsSet(pErrInfo))
528 RTErrInfoSetF(pErrInfo, rc, "RTLdrGetBits failed");
529 return rc;
530 }
531
532 /*
533 * Get the entry points.
534 */
535 RTUINTPTR VMMR0EntryFast = 0;
536 RTUINTPTR VMMR0EntryEx = 0;
537 RTUINTPTR SrvReqHandler = 0;
538 RTUINTPTR ModuleInit = 0;
539 RTUINTPTR ModuleTerm = 0;
540 const char *pszEp = NULL;
541 if (fIsVMMR0)
542 {
543 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
544 UINT32_MAX, pszEp = "VMMR0EntryFast", &VMMR0EntryFast);
545 if (RT_SUCCESS(rc))
546 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
547 UINT32_MAX, pszEp = "VMMR0EntryEx", &VMMR0EntryEx);
548 }
549 else if (pszSrvReqHandler)
550 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
551 UINT32_MAX, pszEp = pszSrvReqHandler, &SrvReqHandler);
552 if (RT_SUCCESS(rc))
553 {
554 int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
555 UINT32_MAX, pszEp = "ModuleInit", &ModuleInit);
556 if (RT_FAILURE(rc2))
557 ModuleInit = 0;
558
559 rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
560 UINT32_MAX, pszEp = "ModuleTerm", &ModuleTerm);
561 if (RT_FAILURE(rc2))
562 ModuleTerm = 0;
563 }
564 if (RT_FAILURE(rc))
565 {
566 LogRel(("SUP: Failed to get entry point '%s' for %s (%s) rc=%Rrc\n", pszEp, pszModule, pszFilename, rc));
567 return RTErrInfoSetF(pErrInfo, rc, "Failed to resolve entry point '%s'", pszEp);
568 }
569
570 /*
571 * Create the symbol and string tables.
572 */
573 SUPLDRCREATETABSARGS CreateArgs;
574 CreateArgs.cbImage = cbImage;
575 CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab];
576 CreateArgs.pszBase = (char *)&pLoadReq->u.In.abImage[offStrTab];
577 CreateArgs.psz = CreateArgs.pszBase;
578 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
579 if (RT_FAILURE(rc))
580 {
581 LogRel(("SUP: RTLdrEnumSymbols failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
582 return RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #2 failed");
583 }
584 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= cbStrTab);
585 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= cSymbols);
586
587 /*
588 * Create the segment table.
589 */
590 SUPLDRCOMPSEGTABARGS SegArgs;
591 SegArgs.uStartRva = 0;
592 SegArgs.uEndRva = 0;
593 SegArgs.fProt = RTMEM_PROT_READ;
594 SegArgs.iSegs = 0;
595 SegArgs.cSegsAlloc = cSegments;
596 SegArgs.paSegs = (PSUPLDRSEG)&pLoadReq->u.In.abImage[offSegTab];
597 SegArgs.pErrInfo = pErrInfo;
598 rc = RTLdrEnumSegments(hLdrMod, supLoadModuleCompileSegmentsCB, &SegArgs);
599 if (RT_FAILURE(rc))
600 {
601 LogRel(("SUP: RTLdrEnumSegments failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
602 return RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSegments #2 failed");
603 }
604 SegArgs.uEndRva = (uint32_t)cbImage;
605 AssertReturn(SegArgs.uEndRva == cbImage, VERR_OUT_OF_RANGE);
606 if (SegArgs.uEndRva > SegArgs.uStartRva)
607 {
608 SegArgs.paSegs[SegArgs.iSegs].off = SegArgs.uStartRva;
609 SegArgs.paSegs[SegArgs.iSegs].cb = SegArgs.uEndRva - SegArgs.uStartRva;
610 SegArgs.paSegs[SegArgs.iSegs].fProt = SegArgs.fProt;
611 SegArgs.paSegs[SegArgs.iSegs].fUnused = 0;
612 SegArgs.iSegs++;
613 }
614 for (uint32_t i = 0; i < SegArgs.iSegs; i++)
615 LogRel(("SUP: seg #%u: %c%c%c %#010RX32 LB %#010RX32\n", i, /** @todo LogRel2 */
616 SegArgs.paSegs[i].fProt & SUPLDR_PROT_READ ? 'R' : ' ',
617 SegArgs.paSegs[i].fProt & SUPLDR_PROT_WRITE ? 'W' : ' ',
618 SegArgs.paSegs[i].fProt & SUPLDR_PROT_EXEC ? 'X' : ' ',
619 SegArgs.paSegs[i].off, SegArgs.paSegs[i].cb));
620 AssertRelease(SegArgs.iSegs == cSegments);
621 AssertRelease(SegArgs.cSegsAlloc == cSegments);
622
623 /*
624 * Upload the image.
625 */
626 pLoadReq->Hdr.u32Cookie = g_u32Cookie;
627 pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
628 pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImageWithEverything);
629 pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
630 pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
631 pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
632
633 pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
634 pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
635 if (fIsVMMR0)
636 {
637 pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
638 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast = (RTR0PTR)VMMR0EntryFast;
639 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
640 }
641 else if (pszSrvReqHandler)
642 {
643 pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
644 pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
645 pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
646 pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
647 pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
648 }
649 else
650 pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
651 pLoadReq->u.In.offStrTab = offStrTab;
652 pLoadReq->u.In.cbStrTab = (uint32_t)cbStrTab;
653 AssertRelease(pLoadReq->u.In.cbStrTab == cbStrTab);
654 pLoadReq->u.In.cbImageBits = (uint32_t)cbImage;
655 pLoadReq->u.In.offSymbols = offSymTab;
656 pLoadReq->u.In.cSymbols = cSymbols;
657 pLoadReq->u.In.offSegments = offSegTab;
658 pLoadReq->u.In.cSegments = cSegments;
659 pLoadReq->u.In.cbImageWithEverything = cbImageWithEverything;
660 pLoadReq->u.In.pvImageBase = uImageBase;
661 pLoadReq->u.In.fFlags = Args.fLoadReq;
662 if (!g_uSupFakeMode)
663 {
664 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything));
665 if (RT_SUCCESS(rc))
666 rc = pLoadReq->Hdr.rc;
667 else
668 LogRel(("SUP: SUP_IOCTL_LDR_LOAD ioctl for %s (%s) failed rc=%Rrc\n", pszModule, pszFilename, rc));
669 }
670 else
671 rc = VINF_SUCCESS;
672 if ( RT_SUCCESS(rc)
673 || rc == VERR_ALREADY_LOADED /* A competing process. */
674 )
675 {
676 LogRel(("SUP: Loaded %s (%s) at %#RKv - ModuleInit at %RKv and ModuleTerm at %RKv%s\n",
677 pszModule, pszFilename, uImageBase, (RTR0PTR)ModuleInit, (RTR0PTR)ModuleTerm,
678 fNativeLoader ? " using the native ring-0 loader" : ""));
679 if (fIsVMMR0)
680 {
681 g_pvVMMR0 = uImageBase;
682 LogRel(("SUP: VMMR0EntryEx located at %RKv and VMMR0EntryFast at %RKv\n", (RTR0PTR)VMMR0EntryEx, (RTR0PTR)VMMR0EntryFast));
683 }
684#ifdef RT_OS_WINDOWS
685 LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, uImageBase));
686#endif
687 return VINF_SUCCESS;
688 }
689
690 /*
691 * Failed, bail out.
692 */
693 LogRel(("SUP: Loading failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
694 if ( pLoadReq->u.Out.uErrorMagic == SUPLDRLOAD_ERROR_MAGIC
695 && pLoadReq->u.Out.szError[0] != '\0')
696 {
697 LogRel(("SUP: %s\n", pLoadReq->u.Out.szError));
698 return RTErrInfoSet(pErrInfo, rc, pLoadReq->u.Out.szError);
699 }
700 return RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_LOAD failed");
701}
702
703
704/**
705 * Worker for SUPR3LoadModule().
706 *
707 * @returns VBox status code.
708 * @param pszFilename Name of the VMMR0 image file
709 * @param pszModule The modulen name.
710 * @param pszSrvReqHandler The service request handler symbol name,
711 * optional.
712 * @param pErrInfo Where to store detailed error info. Optional.
713 * @param ppvImageBase Where to return the load address.
714 */
715static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler,
716 PRTERRINFO pErrInfo, void **ppvImageBase)
717{
718 SUPLDROPEN OpenReq;
719
720 /*
721 * Validate input.
722 */
723 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
724 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
725 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
726 AssertReturn(strlen(pszModule) < sizeof(OpenReq.u.In.szName), VERR_FILENAME_TOO_LONG);
727
728 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
729 AssertReturn(!pszSrvReqHandler || !fIsVMMR0, VERR_INTERNAL_ERROR);
730 *ppvImageBase = NULL;
731
732 /*
733 * First try open it w/o preparing a binary for loading.
734 *
735 * This will be a lot faster if it's already loaded, and it will
736 * avoid fixup issues when using wrapped binaries. With wrapped
737 * ring-0 binaries not all binaries need to be wrapped, so trying
738 * to load it ourselves is not a bug, but intentional behaviour
739 * (even it it asserts in the loader code).
740 */
741 OpenReq.Hdr.u32Cookie = g_u32Cookie;
742 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
743 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
744 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
745 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
746 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
747 OpenReq.u.In.cbImageWithEverything = 0;
748 OpenReq.u.In.cbImageBits = 0;
749 strcpy(OpenReq.u.In.szName, pszModule);
750 int rc = RTPathAbs(pszFilename, OpenReq.u.In.szFilename, sizeof(OpenReq.u.In.szFilename));
751 if (RT_FAILURE(rc))
752 return rc;
753 if ( (SUPDRV_IOC_VERSION & 0xffff0000) != 0x00300000
754 || g_uSupSessionVersion >= 0x00300001)
755 {
756 if (!g_uSupFakeMode)
757 {
758 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
759 if (RT_SUCCESS(rc))
760 rc = OpenReq.Hdr.rc;
761 }
762 else
763 {
764 OpenReq.u.Out.fNeedsLoading = true;
765 OpenReq.u.Out.pvImageBase = 0xef423420;
766 }
767 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
768 if (rc != VERR_MODULE_NOT_FOUND)
769 {
770 if (fIsVMMR0)
771 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
772 LogRel(("SUP: Opened %s (%s) at %#RKv%s.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase,
773 OpenReq.u.Out.fNativeLoader ? " loaded by the native ring-0 loader" : ""));
774#ifdef RT_OS_WINDOWS
775 LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, OpenReq.u.Out.pvImageBase));
776#endif
777 return rc;
778 }
779 }
780
781 /*
782 * Open image file and figure its size.
783 */
784 RTLDRMOD hLdrMod;
785 rc = RTLdrOpenEx(OpenReq.u.In.szFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod, pErrInfo);
786 if (RT_FAILURE(rc))
787 {
788 LogRel(("SUP: RTLdrOpen failed for %s (%s) %Rrc\n", pszModule, OpenReq.u.In.szFilename, rc));
789 return rc;
790 }
791
792 SUPLDRCALCSIZEARGS CalcArgs;
793 CalcArgs.cbStrings = 0;
794 CalcArgs.cSymbols = 0;
795 CalcArgs.cbImage = RTLdrSize(hLdrMod);
796 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
797 if (RT_SUCCESS(rc))
798 {
799 /*
800 * Figure out the number of segments needed first.
801 */
802 SUPLDRCOMPSEGTABARGS SegArgs;
803 SegArgs.uStartRva = 0;
804 SegArgs.uEndRva = 0;
805 SegArgs.fProt = RTMEM_PROT_READ;
806 SegArgs.iSegs = 0;
807 SegArgs.cSegsAlloc = 0;
808 SegArgs.paSegs = NULL;
809 SegArgs.pErrInfo = pErrInfo;
810 rc = RTLdrEnumSegments(hLdrMod, supLoadModuleCompileSegmentsCB, &SegArgs);
811 if (RT_SUCCESS(rc))
812 {
813 Assert(SegArgs.uEndRva <= RTLdrSize(hLdrMod));
814 SegArgs.uEndRva = (uint32_t)CalcArgs.cbImage; /* overflow is checked later */
815 if (SegArgs.uEndRva > SegArgs.uStartRva)
816 {
817 Log2(("supLoadModule: SUP Seg #%u: %#x LB %#x prot %#x\n",
818 SegArgs.iSegs, SegArgs.uStartRva, SegArgs.uEndRva - SegArgs.uStartRva, SegArgs.fProt));
819 SegArgs.iSegs++;
820 }
821
822 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
823 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
824 const uint32_t offSegTab = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
825 const uint32_t cbImageWithEverything = RT_ALIGN_32(offSegTab + sizeof(SUPLDRSEG) * SegArgs.iSegs, 8);
826
827 /*
828 * Open the R0 image.
829 */
830 OpenReq.Hdr.u32Cookie = g_u32Cookie;
831 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
832 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
833 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
834 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
835 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
836 OpenReq.u.In.cbImageWithEverything = cbImageWithEverything;
837 OpenReq.u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
838 strcpy(OpenReq.u.In.szName, pszModule);
839 rc = RTPathAbs(pszFilename, OpenReq.u.In.szFilename, sizeof(OpenReq.u.In.szFilename));
840 AssertRC(rc);
841 if (RT_SUCCESS(rc))
842 {
843 if (!g_uSupFakeMode)
844 {
845 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
846 if (RT_SUCCESS(rc))
847 rc = OpenReq.Hdr.rc;
848 }
849 else
850 {
851 OpenReq.u.Out.fNeedsLoading = true;
852 OpenReq.u.Out.pvImageBase = 0xef423420;
853 }
854 }
855 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
856 if ( RT_SUCCESS(rc)
857 && OpenReq.u.Out.fNeedsLoading)
858 {
859 /*
860 * We need to load it.
861 *
862 * Allocate the request and pass it to an inner work function
863 * that populates it and sends it off to the driver.
864 */
865 const uint32_t cbLoadReq = SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything);
866 PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(cbLoadReq);
867 if (pLoadReq)
868 {
869 rc = supLoadModuleInner(hLdrMod, pLoadReq, cbImageWithEverything, OpenReq.u.Out.pvImageBase, CalcArgs.cbImage,
870 pszModule, pszFilename, OpenReq.u.Out.fNativeLoader, fIsVMMR0, pszSrvReqHandler,
871 offSymTab, CalcArgs.cSymbols,
872 offStrTab, CalcArgs.cbStrings,
873 offSegTab, SegArgs.iSegs,
874 pErrInfo);
875 RTMemTmpFree(pLoadReq);
876 }
877 else
878 {
879 AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything)));
880 rc = RTErrInfoSetF(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %u bytes for the load request",
881 SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything));
882 }
883 }
884 /*
885 * Already loaded?
886 */
887 else if (RT_SUCCESS(rc))
888 {
889 if (fIsVMMR0)
890 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
891 LogRel(("SUP: Opened %s (%s) at %#RKv%s.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase,
892 OpenReq.u.Out.fNativeLoader ? " loaded by the native ring-0 loader" : ""));
893#ifdef RT_OS_WINDOWS
894 LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, OpenReq.u.Out.pvImageBase));
895#endif
896 }
897 /*
898 * No, failed.
899 */
900 else
901 RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_OPEN failed");
902 }
903 else if (!RTErrInfoIsSet(pErrInfo) && pErrInfo)
904 RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSegments #1 failed");
905 }
906 else
907 RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #1 failed");
908 RTLdrClose(hLdrMod);
909 return rc;
910}
911
912
913SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase)
914{
915 /* fake */
916 if (RT_UNLIKELY(g_uSupFakeMode))
917 {
918 g_pvVMMR0 = NIL_RTR0PTR;
919 return VINF_SUCCESS;
920 }
921
922 /*
923 * Free the requested module.
924 */
925 SUPLDRFREE Req;
926 Req.Hdr.u32Cookie = g_u32Cookie;
927 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
928 Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
929 Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
930 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
931 Req.Hdr.rc = VERR_INTERNAL_ERROR;
932 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
933 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
934 if (RT_SUCCESS(rc))
935 rc = Req.Hdr.rc;
936 if ( RT_SUCCESS(rc)
937 && (RTR0PTR)pvImageBase == g_pvVMMR0)
938 g_pvVMMR0 = NIL_RTR0PTR;
939 return rc;
940}
941
942
943SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
944{
945 *ppvValue = NULL;
946
947 /* fake */
948 if (RT_UNLIKELY(g_uSupFakeMode))
949 {
950 *ppvValue = (void *)(uintptr_t)0xdeadf00d;
951 return VINF_SUCCESS;
952 }
953
954 /*
955 * Do ioctl.
956 */
957 SUPLDRGETSYMBOL Req;
958 Req.Hdr.u32Cookie = g_u32Cookie;
959 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
960 Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
961 Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
962 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
963 Req.Hdr.rc = VERR_INTERNAL_ERROR;
964 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
965 size_t cchSymbol = strlen(pszSymbol);
966 if (cchSymbol >= sizeof(Req.u.In.szSymbol))
967 return VERR_SYMBOL_NOT_FOUND;
968 memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
969 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
970 if (RT_SUCCESS(rc))
971 rc = Req.Hdr.rc;
972 if (RT_SUCCESS(rc))
973 *ppvValue = (void *)Req.u.Out.pvSymbol;
974 return rc;
975}
976
977
978SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename, PRTERRINFO pErrInfo)
979{
980 void *pvImageBase;
981 return SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase, pErrInfo);
982}
983
984
985SUPR3DECL(int) SUPR3UnloadVMM(void)
986{
987 return SUPR3FreeModule((void*)g_pvVMMR0);
988}
989
990
991/**
992 * Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
993 *
994 * @returns iprt status code.
995 * @param pszFilename The full file name.
996 * @param phLdrMod Where to store the handle to the loaded module.
997 * @param fFlags See RTLDFLAGS_.
998 * @param pErrInfo Where to return extended error information.
999 * Optional.
1000 *
1001 */
1002static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
1003{
1004#ifdef VBOX_WITH_HARDENING
1005 /*
1006 * Verify the image file.
1007 */
1008 int rc = SUPR3HardenedVerifyInit();
1009 if (RT_FAILURE(rc))
1010 rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
1011 if (RT_FAILURE(rc))
1012 {
1013 LogRel(("supR3HardenedLdrLoadIt: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1014 return RTErrInfoSet(pErrInfo, rc, "supR3HardenedVerifyFixedFile failed");
1015 }
1016#endif
1017
1018 /*
1019 * Try load it.
1020 */
1021 return RTLdrLoadEx(pszFilename, phLdrMod, fFlags, pErrInfo);
1022}
1023
1024
1025SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
1026{
1027 /*
1028 * Validate input.
1029 */
1030 RTErrInfoClear(pErrInfo);
1031 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1032 AssertPtrReturn(phLdrMod, VERR_INVALID_POINTER);
1033 *phLdrMod = NIL_RTLDRMOD;
1034 AssertReturn(RTPathHavePath(pszFilename), VERR_INVALID_PARAMETER);
1035
1036 /*
1037 * Add the default extension if it's missing.
1038 */
1039 if (!RTPathHasSuffix(pszFilename))
1040 {
1041 const char *pszSuff = RTLdrGetSuff();
1042 size_t cchSuff = strlen(pszSuff);
1043 size_t cchFilename = strlen(pszFilename);
1044 char *psz = (char *)alloca(cchFilename + cchSuff + 1);
1045 AssertReturn(psz, VERR_NO_TMP_MEMORY);
1046 memcpy(psz, pszFilename, cchFilename);
1047 memcpy(psz + cchFilename, pszSuff, cchSuff + 1);
1048 pszFilename = psz;
1049 }
1050
1051 /*
1052 * Pass it on to the common library loader.
1053 */
1054 return supR3HardenedLdrLoadIt(pszFilename, phLdrMod, fFlags, pErrInfo);
1055}
1056
1057
1058SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
1059{
1060 LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p fFlags=%08x pErrInfo=%p\n", pszFilename, pszFilename, phLdrMod, fFlags, pErrInfo));
1061
1062 /*
1063 * Validate input.
1064 */
1065 RTErrInfoClear(pErrInfo);
1066 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
1067 *phLdrMod = NIL_RTLDRMOD;
1068 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1069 AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
1070
1071 /*
1072 * Check the filename.
1073 */
1074 size_t cchFilename = strlen(pszFilename);
1075 AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
1076
1077 const char *pszExt = "";
1078 size_t cchExt = 0;
1079 if (!RTPathHasSuffix(pszFilename))
1080 {
1081 pszExt = RTLdrGetSuff();
1082 cchExt = strlen(pszExt);
1083 }
1084
1085 /*
1086 * Construct the private arch path and check if the file exists.
1087 */
1088 char szPath[RTPATH_MAX];
1089 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchExt - cchFilename);
1090 AssertRCReturn(rc, rc);
1091
1092 char *psz = strchr(szPath, '\0');
1093 *psz++ = RTPATH_SLASH;
1094 memcpy(psz, pszFilename, cchFilename);
1095 psz += cchFilename;
1096 memcpy(psz, pszExt, cchExt + 1);
1097
1098 if (!RTPathExists(szPath))
1099 {
1100 LogRel(("SUPR3HardenedLdrLoadAppPriv: \"%s\" not found\n", szPath));
1101 return VERR_FILE_NOT_FOUND;
1102 }
1103
1104 /*
1105 * Pass it on to SUPR3HardenedLdrLoad.
1106 */
1107 rc = SUPR3HardenedLdrLoad(szPath, phLdrMod, fFlags, pErrInfo);
1108
1109 LogFlow(("SUPR3HardenedLdrLoadAppPriv: returns %Rrc\n", rc));
1110 return rc;
1111}
1112
1113
1114SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
1115{
1116 /*
1117 * Validate input.
1118 */
1119 RTErrInfoClear(pErrInfo);
1120 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
1121 *phLdrMod = NIL_RTLDRMOD;
1122 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1123 AssertReturn(RTPathStartsWithRoot(pszFilename), VERR_INVALID_PARAMETER);
1124
1125#ifdef VBOX_WITH_HARDENING
1126 /*
1127 * Verify the image file.
1128 */
1129 int rc = supR3HardenedVerifyFile(pszFilename, RTHCUINTPTR_MAX, true /*fMaybe3rdParty*/, pErrInfo);
1130 if (RT_FAILURE(rc))
1131 {
1132 if (!RTErrInfoIsSet(pErrInfo))
1133 LogRel(("supR3HardenedVerifyFile: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1134 return rc;
1135 }
1136#endif
1137
1138 /*
1139 * Try load it.
1140 */
1141 return RTLdrLoadEx(pszFilename, phLdrMod, RTLDRLOAD_FLAGS_LOCAL, pErrInfo);
1142}
1143
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use