VirtualBox

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

Last change on this file since 91392 was 90862, checked in by vboxsync, 3 years ago

IPRT,SUPDrv,VMM,++: Bumped major support driver version. Added RTLogSetR0ProgramStart and make the VMM use it when configuring the ring-0 loggers. Removed pfnFlush from the parameter list of RTLogCreateEx[V]. bugref:10086

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