VirtualBox

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

Last change on this file since 85511 was 85511, checked in by vboxsync, 5 years ago

SUP,*: Some changes to the SUP_IOCTL_LDR_OPEN and SUP_IOCTL_LDR_LOAD interfaces adding memory protection regions for better WX compliance. Preps for linux 5.8 where we'll be using RTR0MemObjAllocPage rather than RTMemExecAlloc for images, switch from relocatable ELF files to shared objects. [build fix] bugref:9801

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.3 KB
Line 
1/* $Id: SUPLibLdr.cpp 85511 2020-07-29 10:21:19Z 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.215389.xyz. 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} SUPLDRRESIMPARGS, *PSUPLDRRESIMPARGS;
128
129/**
130 * Resolve an external symbol during RTLdrGetBits().
131 *
132 * @returns VBox status code.
133 * @param hLdrMod The loader module handle.
134 * @param pszModule Module name.
135 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
136 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
137 * @param pValue Where to store the symbol value (address).
138 * @param pvUser User argument.
139 */
140static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
141 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
142{
143 NOREF(hLdrMod); NOREF(uSymbol);
144 AssertPtr(pValue);
145 AssertPtr(pvUser);
146 PSUPLDRRESIMPARGS pArgs = (PSUPLDRRESIMPARGS)pvUser;
147
148 /*
149 * Only SUPR0 and VMMR0.r0
150 */
151 if ( pszModule
152 && *pszModule
153 && strcmp(pszModule, "VBoxDrv.sys")
154 && strcmp(pszModule, "VMMR0.r0"))
155 {
156#if defined(RT_OS_WINDOWS) && 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrv-win.cpp */
157 if (strcmp(pszModule, "ntoskrnl.exe") == 0)
158 {
159 *pValue = 42; /* Non-zero so ring-0 can find the end of the IAT and exclude it when comparing. */
160 return VINF_SUCCESS;
161 }
162#endif
163 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pArgs->pszModule, pszModule));
164 return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
165 "Unexpected import module '%s' in '%s'", pszModule, pArgs->pszModule);
166 }
167
168 /*
169 * No ordinals.
170 */
171 if (uSymbol != ~0U)
172 {
173 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pArgs->pszModule, uSymbol));
174 return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
175 "Unexpected ordinal import (%#x) in '%s'", uSymbol, pArgs->pszModule);
176 }
177
178 /*
179 * Lookup symbol.
180 */
181 /* Skip the 64-bit ELF import prefix first. */
182 /** @todo is this actually used??? */
183 if (!strncmp(pszSymbol, RT_STR_TUPLE("SUPR0$")))
184 pszSymbol += sizeof("SUPR0$") - 1;
185
186 /*
187 * Check the VMMR0.r0 module if loaded.
188 */
189 /** @todo call the SUPR3LoadModule caller.... */
190 /** @todo proper reference counting and such. */
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 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 /* Ignore segments not part of the loaded image. */
362 if (pSeg->RVA == NIL_RTLDRADDR || pSeg->cbMapped == 0)
363 return VINF_SUCCESS;
364
365 /* We currently ASSUME that all relevant segments are in ascending RVA order. */
366 AssertReturn(pSeg->RVA >= pArgs->uEndRva,
367 RTERRINFO_LOG_REL_SET_F(pArgs->pErrInfo, VERR_BAD_EXE_FORMAT, "Out of order segment: %p LB %#zx #%.*s",
368 pSeg->RVA, pSeg->cb, pSeg->cchName, pSeg->pszName));
369
370 /* We ASSUME the cbMapped field is implemented. */
371 AssertReturn(pSeg->cbMapped != NIL_RTLDRADDR, VERR_INTERNAL_ERROR_2);
372 AssertReturn(pSeg->cbMapped < _1G, VERR_INTERNAL_ERROR_4);
373 uint32_t cbMapped = (uint32_t)pSeg->cbMapped;
374 AssertReturn(pSeg->RVA < _1G, VERR_INTERNAL_ERROR_3);
375 uint32_t uRvaSeg = (uint32_t)pSeg->RVA;
376 Log2(("supLoadModuleCompileSegmentsCB: %RTptr/%RTptr LB %RTptr prot %#x %s\n",
377 pSeg->LinkAddress, pSeg->RVA, pSeg->cbMapped, pSeg->fProt, pSeg->pszName));
378
379 /*
380 * If the protection is the same as the previous segment,
381 * just update uEndRva and continue.
382 */
383 uint32_t fProt = pSeg->fProt;
384#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
385 if (fProt & RTMEM_PROT_EXEC)
386 fProt |= fProt & RTMEM_PROT_READ;
387#endif
388 if (pSeg->fProt == pArgs->fProt)
389 {
390 pArgs->uEndRva = uRvaSeg + cbMapped;
391 Log2(("supLoadModuleCompileSegmentsCB: -> merged\n"));
392 return VINF_SUCCESS;
393 }
394
395 /*
396 * The protection differs, so commit current segment and start a new one.
397 * However, if the new segment and old segment share a page, this becomes
398 * a little more complicated...
399 */
400 if (pArgs->uStartRva < pArgs->uEndRva)
401 {
402 if (((pArgs->uEndRva - 1) >> PAGE_SHIFT) != (uRvaSeg >> PAGE_SHIFT))
403 {
404 /* No common page, so make the new segment start on a page boundrary. */
405 cbMapped += uRvaSeg & PAGE_OFFSET_MASK;
406 uRvaSeg &= ~(uint32_t)PAGE_OFFSET_MASK;
407 Assert(pArgs->uEndRva <= uRvaSeg);
408 Log2(("supLoadModuleCompileSegmentsCB: -> new, no common\n"));
409 }
410 else if ((fProt & pArgs->fProt) == fProt)
411 {
412 /* The current segment includes the memory protections of the
413 previous, so include the common page in it: */
414 uint32_t const cbCommon = PAGE_SIZE - (uRvaSeg & PAGE_OFFSET_MASK);
415 if (cbCommon >= cbMapped)
416 {
417 pArgs->uEndRva = uRvaSeg + cbMapped;
418 Log2(("supLoadModuleCompileSegmentsCB: -> merge, %#x common, upgrading prot to %#x\n", cbCommon, pArgs->fProt));
419 return VINF_SUCCESS; /* New segment was smaller than a page. */
420 }
421 cbMapped -= cbCommon;
422 uRvaSeg += cbCommon;
423 Assert(pArgs->uEndRva <= uRvaSeg);
424 Log2(("supLoadModuleCompileSegmentsCB: -> new, %#x common into previous\n", cbCommon));
425 }
426 else if ((fProt & pArgs->fProt) == pArgs->fProt)
427 {
428 /* The new segment includes the memory protections of the
429 previous, so include the common page in it: */
430 cbMapped += uRvaSeg & PAGE_OFFSET_MASK;
431 uRvaSeg &= ~(uint32_t)PAGE_OFFSET_MASK;
432 if (uRvaSeg == pArgs->uStartRva)
433 {
434 pArgs->fProt = fProt;
435 pArgs->uEndRva = uRvaSeg + cbMapped;
436 Log2(("supLoadModuleCompileSegmentsCB: -> upgrade current protection\n"));
437 return VINF_SUCCESS; /* Current segment was smaller than a page. */
438 }
439 Log2(("supLoadModuleCompileSegmentsCB: -> new, %#x common into new\n", (uint32_t)(pSeg->RVA & PAGE_OFFSET_MASK)));
440 }
441 else
442 {
443 /* Create a new segment for the common page with the combined protection. */
444 Log2(("supLoadModuleCompileSegmentsCB: -> its complicated...\n"));
445 pArgs->uEndRva &= ~(uint32_t)PAGE_OFFSET_MASK;
446 if (pArgs->uEndRva > pArgs->uStartRva)
447 {
448 Log2(("supLoadModuleCompileSegmentsCB: SUP Seg #%u: %#x LB %#x prot %#x\n",
449 pArgs->iSegs, pArgs->uStartRva, pArgs->uEndRva - pArgs->uStartRva, pArgs->fProt));
450 if (pArgs->paSegs)
451 {
452 AssertReturn(pArgs->iSegs < pArgs->cSegsAlloc, VERR_INTERNAL_ERROR_5);
453 pArgs->paSegs[pArgs->iSegs].off = pArgs->uStartRva;
454 pArgs->paSegs[pArgs->iSegs].cb = pArgs->uEndRva - pArgs->uStartRva;
455 pArgs->paSegs[pArgs->iSegs].fProt = pArgs->fProt;
456 }
457 pArgs->iSegs++;
458 pArgs->uStartRva = pArgs->uEndRva;
459 }
460 pArgs->fProt |= fProt;
461
462 uint32_t const cbCommon = PAGE_SIZE - (uRvaSeg & PAGE_OFFSET_MASK);
463 if (cbCommon <= cbMapped)
464 {
465 fProt |= pArgs->fProt;
466 pArgs->uEndRva = uRvaSeg + cbMapped;
467 return VINF_SUCCESS; /* New segment was smaller than a page. */
468 }
469 cbMapped -= cbCommon;
470 uRvaSeg += cbCommon;
471 Assert(uRvaSeg - pArgs->uStartRva == PAGE_SIZE);
472 }
473
474 /* The current segment should end where the new one starts, no gaps. */
475 pArgs->uEndRva = uRvaSeg;
476
477 /* Emit the current segment */
478 Log2(("supLoadModuleCompileSegmentsCB: SUP Seg #%u: %#x LB %#x prot %#x\n",
479 pArgs->iSegs, pArgs->uStartRva, pArgs->uEndRva - pArgs->uStartRva, pArgs->fProt));
480 if (pArgs->paSegs)
481 {
482 AssertReturn(pArgs->iSegs < pArgs->cSegsAlloc, VERR_INTERNAL_ERROR_5);
483 pArgs->paSegs[pArgs->iSegs].off = pArgs->uStartRva;
484 pArgs->paSegs[pArgs->iSegs].cb = pArgs->uEndRva - pArgs->uStartRva;
485 pArgs->paSegs[pArgs->iSegs].fProt = pArgs->fProt;
486 }
487 pArgs->iSegs++;
488 }
489 /* else: current segment is empty */
490
491 /* Start the new segment. */
492 Assert(!(uRvaSeg & PAGE_OFFSET_MASK));
493 pArgs->fProt = fProt;
494 pArgs->uStartRva = uRvaSeg;
495 pArgs->uEndRva = uRvaSeg + cbMapped;
496 return VINF_SUCCESS;
497}
498
499
500/**
501 * Worker for supLoadModule().
502 */
503static int supLoadModuleInner(RTLDRMOD hLdrMod, PSUPLDRLOAD pLoadReq, uint32_t cbImageWithEverything,
504 RTR0PTR uImageBase, size_t cbImage, const char *pszModule, const char *pszFilename,
505 bool fNativeLoader, bool fIsVMMR0, const char *pszSrvReqHandler,
506 uint32_t offSymTab, uint32_t cSymbols,
507 uint32_t offStrTab, size_t cbStrTab,
508 uint32_t offSegTab, uint32_t cSegments,
509 PRTERRINFO pErrInfo)
510{
511 /*
512 * Get the image bits.
513 */
514 SUPLDRRESIMPARGS Args = { pszModule, pErrInfo };
515 int rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase, supLoadModuleResolveImport, &Args);
516 if (RT_FAILURE(rc))
517 {
518 LogRel(("SUP: RTLdrGetBits failed for %s (%s). rc=%Rrc\n", pszModule, pszFilename, rc));
519 if (!RTErrInfoIsSet(pErrInfo))
520 RTErrInfoSetF(pErrInfo, rc, "RTLdrGetBits failed");
521 return rc;
522 }
523
524 /*
525 * Get the entry points.
526 */
527 RTUINTPTR VMMR0EntryFast = 0;
528 RTUINTPTR VMMR0EntryEx = 0;
529 RTUINTPTR SrvReqHandler = 0;
530 RTUINTPTR ModuleInit = 0;
531 RTUINTPTR ModuleTerm = 0;
532 const char *pszEp = NULL;
533 if (fIsVMMR0)
534 {
535 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
536 UINT32_MAX, pszEp = "VMMR0EntryFast", &VMMR0EntryFast);
537 if (RT_SUCCESS(rc))
538 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
539 UINT32_MAX, pszEp = "VMMR0EntryEx", &VMMR0EntryEx);
540 }
541 else if (pszSrvReqHandler)
542 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
543 UINT32_MAX, pszEp = pszSrvReqHandler, &SrvReqHandler);
544 if (RT_SUCCESS(rc))
545 {
546 int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
547 UINT32_MAX, pszEp = "ModuleInit", &ModuleInit);
548 if (RT_FAILURE(rc2))
549 ModuleInit = 0;
550
551 rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
552 UINT32_MAX, pszEp = "ModuleTerm", &ModuleTerm);
553 if (RT_FAILURE(rc2))
554 ModuleTerm = 0;
555 }
556 if (RT_FAILURE(rc))
557 {
558 LogRel(("SUP: Failed to get entry point '%s' for %s (%s) rc=%Rrc\n", pszEp, pszModule, pszFilename, rc));
559 return RTErrInfoSetF(pErrInfo, rc, "Failed to resolve entry point '%s'", pszEp);
560 }
561
562 /*
563 * Create the symbol and string tables.
564 */
565 SUPLDRCREATETABSARGS CreateArgs;
566 CreateArgs.cbImage = cbImage;
567 CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab];
568 CreateArgs.pszBase = (char *)&pLoadReq->u.In.abImage[offStrTab];
569 CreateArgs.psz = CreateArgs.pszBase;
570 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
571 if (RT_FAILURE(rc))
572 {
573 LogRel(("SUP: RTLdrEnumSymbols failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
574 return RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #2 failed");
575 }
576 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= cbStrTab);
577 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= cSymbols);
578
579 /*
580 * Create the segment table.
581 */
582 SUPLDRCOMPSEGTABARGS SegArgs;
583 SegArgs.uStartRva = 0;
584 SegArgs.uEndRva = 0;
585 SegArgs.fProt = RTMEM_PROT_READ;
586 SegArgs.iSegs = 0;
587 SegArgs.cSegsAlloc = cSegments;
588 SegArgs.paSegs = (PSUPLDRSEG)&pLoadReq->u.In.abImage[offSegTab];
589 SegArgs.pErrInfo = pErrInfo;
590 rc = RTLdrEnumSegments(hLdrMod, supLoadModuleCompileSegmentsCB, &SegArgs);
591 if (RT_FAILURE(rc))
592 {
593 LogRel(("SUP: RTLdrEnumSegments failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
594 return RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSegments #2 failed");
595 }
596 SegArgs.uEndRva = (uint32_t)cbImage;
597 AssertReturn(SegArgs.uEndRva == cbImage, VERR_OUT_OF_RANGE);
598 if (SegArgs.uEndRva > SegArgs.uStartRva)
599 {
600 SegArgs.paSegs[SegArgs.iSegs].off = SegArgs.uStartRva;
601 SegArgs.paSegs[SegArgs.iSegs].cb = SegArgs.uEndRva - SegArgs.uStartRva;
602 SegArgs.paSegs[SegArgs.iSegs].fProt = SegArgs.fProt;
603 SegArgs.iSegs++;
604 }
605 for (uint32_t i = 0; i < SegArgs.iSegs; i++)
606 LogRel(("SUP: seg #%u: %c%c%c %#010RX32 LB %#010RX32\n", i, /** @todo LogRel2 */
607 SegArgs.paSegs[i].fProt & SUPLDR_PROT_READ ? 'R' : ' ',
608 SegArgs.paSegs[i].fProt & SUPLDR_PROT_WRITE ? 'W' : ' ',
609 SegArgs.paSegs[i].fProt & SUPLDR_PROT_EXEC ? 'X' : ' ',
610 SegArgs.paSegs[i].off, SegArgs.paSegs[i].cb));
611 AssertRelease(SegArgs.iSegs == cSegments);
612 AssertRelease(SegArgs.cSegsAlloc == cSegments);
613
614 /*
615 * Upload the image.
616 */
617 pLoadReq->Hdr.u32Cookie = g_u32Cookie;
618 pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
619 pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImageWithEverything);
620 pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
621 pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
622 pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
623
624 pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
625 pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
626 if (fIsVMMR0)
627 {
628 pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
629 pLoadReq->u.In.EP.VMMR0.pvVMMR0 = uImageBase;
630 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
631 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
632 }
633 else if (pszSrvReqHandler)
634 {
635 pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
636 pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
637 pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
638 pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
639 pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
640 }
641 else
642 pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
643 pLoadReq->u.In.offStrTab = offStrTab;
644 pLoadReq->u.In.cbStrTab = (uint32_t)cbStrTab;
645 AssertRelease(pLoadReq->u.In.cbStrTab == cbStrTab);
646 pLoadReq->u.In.cbImageBits = (uint32_t)cbImage;
647 pLoadReq->u.In.offSymbols = offSymTab;
648 pLoadReq->u.In.cSymbols = cSymbols;
649 pLoadReq->u.In.offSegments = offSegTab;
650 pLoadReq->u.In.cSegments = cSegments;
651 pLoadReq->u.In.cbImageWithEverything = cbImageWithEverything;
652 pLoadReq->u.In.pvImageBase = uImageBase;
653 if (!g_uSupFakeMode)
654 {
655 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything));
656 if (RT_SUCCESS(rc))
657 rc = pLoadReq->Hdr.rc;
658 else
659 LogRel(("SUP: SUP_IOCTL_LDR_LOAD ioctl for %s (%s) failed rc=%Rrc\n", pszModule, pszFilename, rc));
660 }
661 else
662 rc = VINF_SUCCESS;
663 if ( RT_SUCCESS(rc)
664 || rc == VERR_ALREADY_LOADED /* A competing process. */
665 )
666 {
667 LogRel(("SUP: Loaded %s (%s) at %#RKv - ModuleInit at %RKv and ModuleTerm at %RKv%s\n",
668 pszModule, pszFilename, uImageBase, (RTR0PTR)ModuleInit, (RTR0PTR)ModuleTerm,
669 fNativeLoader ? " using the native ring-0 loader" : ""));
670 if (fIsVMMR0)
671 {
672 g_pvVMMR0 = uImageBase;
673 LogRel(("SUP: VMMR0EntryEx located at %RKv and VMMR0EntryFast at %RKv\n", (RTR0PTR)VMMR0EntryEx, (RTR0PTR)VMMR0EntryFast));
674 }
675#ifdef RT_OS_WINDOWS
676 LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, uImageBase));
677#endif
678 return VINF_SUCCESS;
679 }
680
681 /*
682 * Failed, bail out.
683 */
684 LogRel(("SUP: Loading failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
685 if ( pLoadReq->u.Out.uErrorMagic == SUPLDRLOAD_ERROR_MAGIC
686 && pLoadReq->u.Out.szError[0] != '\0')
687 {
688 LogRel(("SUP: %s\n", pLoadReq->u.Out.szError));
689 return RTErrInfoSet(pErrInfo, rc, pLoadReq->u.Out.szError);
690 }
691 return RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_LOAD failed");
692}
693
694
695/**
696 * Worker for SUPR3LoadModule().
697 *
698 * @returns VBox status code.
699 * @param pszFilename Name of the VMMR0 image file
700 * @param pszModule The modulen name.
701 * @param pszSrvReqHandler The service request handler symbol name,
702 * optional.
703 * @param pErrInfo Where to store detailed error info. Optional.
704 * @param ppvImageBase Where to return the load address.
705 */
706static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler,
707 PRTERRINFO pErrInfo, void **ppvImageBase)
708{
709 int rc;
710
711 /*
712 * Validate input.
713 */
714 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
715 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
716 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
717 /** @todo abspath it right into SUPLDROPEN */
718 AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
719 char szAbsFilename[RT_SIZEOFMEMB(SUPLDROPEN, u.In.szFilename)];
720 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
721 if (RT_FAILURE(rc))
722 return rc;
723 pszFilename = szAbsFilename;
724
725 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
726 AssertReturn(!pszSrvReqHandler || !fIsVMMR0, VERR_INTERNAL_ERROR);
727 *ppvImageBase = NULL;
728
729 /*
730 * Open image file and figure its size.
731 */
732 RTLDRMOD hLdrMod;
733 rc = RTLdrOpenEx(pszFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod, pErrInfo);
734 if (RT_FAILURE(rc))
735 {
736 LogRel(("SUP: RTLdrOpen failed for %s (%s) %Rrc\n", pszModule, pszFilename, rc));
737 return rc;
738 }
739
740 SUPLDRCALCSIZEARGS CalcArgs;
741 CalcArgs.cbStrings = 0;
742 CalcArgs.cSymbols = 0;
743 CalcArgs.cbImage = RTLdrSize(hLdrMod);
744 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
745 if (RT_SUCCESS(rc))
746 {
747 /*
748 * Figure out the number of segments needed first.
749 */
750 SUPLDRCOMPSEGTABARGS SegArgs;
751 SegArgs.uStartRva = 0;
752 SegArgs.uEndRva = 0;
753 SegArgs.fProt = RTMEM_PROT_READ;
754 SegArgs.iSegs = 0;
755 SegArgs.cSegsAlloc = 0;
756 SegArgs.paSegs = NULL;
757 SegArgs.pErrInfo = pErrInfo;
758 rc = RTLdrEnumSegments(hLdrMod, supLoadModuleCompileSegmentsCB, &SegArgs);
759 if (RT_SUCCESS(rc))
760 {
761 Assert(SegArgs.uEndRva <= RTLdrSize(hLdrMod));
762 SegArgs.uEndRva = (uint32_t)CalcArgs.cbImage; /* overflow is checked later */
763 if (SegArgs.uEndRva > SegArgs.uStartRva)
764 SegArgs.iSegs++;
765
766 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
767 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
768 const uint32_t offSegTab = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
769 const uint32_t cbImageWithEverything = RT_ALIGN_32(offSegTab + sizeof(SUPLDRSEG) * SegArgs.iSegs, 8);
770
771 /*
772 * Open the R0 image.
773 */
774 SUPLDROPEN OpenReq;
775 OpenReq.Hdr.u32Cookie = g_u32Cookie;
776 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
777 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
778 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
779 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
780 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
781 OpenReq.u.In.cbImageWithEverything = cbImageWithEverything;
782 OpenReq.u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
783 strcpy(OpenReq.u.In.szName, pszModule);
784 strcpy(OpenReq.u.In.szFilename, pszFilename);
785 if (!g_uSupFakeMode)
786 {
787 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
788 if (RT_SUCCESS(rc))
789 rc = OpenReq.Hdr.rc;
790 }
791 else
792 {
793 OpenReq.u.Out.fNeedsLoading = true;
794 OpenReq.u.Out.pvImageBase = 0xef423420;
795 }
796 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
797 if ( RT_SUCCESS(rc)
798 && OpenReq.u.Out.fNeedsLoading)
799 {
800 /*
801 * We need to load it.
802 *
803 * Allocate the request and pass it to an inner work function
804 * that populates it and sends it off to the driver.
805 */
806 const uint32_t cbLoadReq = SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything);
807 PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(cbLoadReq);
808 if (pLoadReq)
809 {
810 rc = supLoadModuleInner(hLdrMod, pLoadReq, cbImageWithEverything, OpenReq.u.Out.pvImageBase, CalcArgs.cbImage,
811 pszModule, pszFilename, OpenReq.u.Out.fNativeLoader, fIsVMMR0, pszSrvReqHandler,
812 offSymTab, CalcArgs.cSymbols,
813 offStrTab, CalcArgs.cbStrings,
814 offSegTab, SegArgs.iSegs,
815 pErrInfo);
816 RTMemTmpFree(pLoadReq);
817 }
818 else
819 {
820 AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything)));
821 rc = RTErrInfoSetF(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %u bytes for the load request",
822 SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything));
823 }
824 }
825 /*
826 * Already loaded?
827 */
828 else if (RT_SUCCESS(rc))
829 {
830 if (fIsVMMR0)
831 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
832 LogRel(("SUP: Opened %s (%s) at %#RKv%s.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase,
833 OpenReq.u.Out.fNativeLoader ? " loaded by the native ring-0 loader" : ""));
834#ifdef RT_OS_WINDOWS
835 LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, OpenReq.u.Out.pvImageBase));
836#endif
837 }
838 /*
839 * No, failed.
840 */
841 else
842 RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_OPEN failed");
843 }
844 else if (!RTErrInfoIsSet(pErrInfo) && pErrInfo)
845 RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSegments #1 failed");
846 }
847 else
848 RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #1 failed");
849 RTLdrClose(hLdrMod);
850 return rc;
851}
852
853
854SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase)
855{
856 /* fake */
857 if (RT_UNLIKELY(g_uSupFakeMode))
858 {
859 g_pvVMMR0 = NIL_RTR0PTR;
860 return VINF_SUCCESS;
861 }
862
863 /*
864 * Free the requested module.
865 */
866 SUPLDRFREE Req;
867 Req.Hdr.u32Cookie = g_u32Cookie;
868 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
869 Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
870 Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
871 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
872 Req.Hdr.rc = VERR_INTERNAL_ERROR;
873 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
874 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
875 if (RT_SUCCESS(rc))
876 rc = Req.Hdr.rc;
877 if ( RT_SUCCESS(rc)
878 && (RTR0PTR)pvImageBase == g_pvVMMR0)
879 g_pvVMMR0 = NIL_RTR0PTR;
880 return rc;
881}
882
883
884SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
885{
886 *ppvValue = NULL;
887
888 /* fake */
889 if (RT_UNLIKELY(g_uSupFakeMode))
890 {
891 *ppvValue = (void *)(uintptr_t)0xdeadf00d;
892 return VINF_SUCCESS;
893 }
894
895 /*
896 * Do ioctl.
897 */
898 SUPLDRGETSYMBOL Req;
899 Req.Hdr.u32Cookie = g_u32Cookie;
900 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
901 Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
902 Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
903 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
904 Req.Hdr.rc = VERR_INTERNAL_ERROR;
905 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
906 size_t cchSymbol = strlen(pszSymbol);
907 if (cchSymbol >= sizeof(Req.u.In.szSymbol))
908 return VERR_SYMBOL_NOT_FOUND;
909 memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
910 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
911 if (RT_SUCCESS(rc))
912 rc = Req.Hdr.rc;
913 if (RT_SUCCESS(rc))
914 *ppvValue = (void *)Req.u.Out.pvSymbol;
915 return rc;
916}
917
918
919SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename, PRTERRINFO pErrInfo)
920{
921 void *pvImageBase;
922 return SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase, pErrInfo);
923}
924
925
926SUPR3DECL(int) SUPR3UnloadVMM(void)
927{
928 return SUPR3FreeModule((void*)g_pvVMMR0);
929}
930
931
932/**
933 * Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
934 *
935 * @returns iprt status code.
936 * @param pszFilename The full file name.
937 * @param phLdrMod Where to store the handle to the loaded module.
938 * @param fFlags See RTLDFLAGS_.
939 * @param pErrInfo Where to return extended error information.
940 * Optional.
941 *
942 */
943static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
944{
945#ifdef VBOX_WITH_HARDENING
946 /*
947 * Verify the image file.
948 */
949 int rc = SUPR3HardenedVerifyInit();
950 if (RT_FAILURE(rc))
951 rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
952 if (RT_FAILURE(rc))
953 {
954 LogRel(("supR3HardenedLdrLoadIt: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
955 return RTErrInfoSet(pErrInfo, rc, "supR3HardenedVerifyFixedFile failed");
956 }
957#endif
958
959 /*
960 * Try load it.
961 */
962 return RTLdrLoadEx(pszFilename, phLdrMod, fFlags, pErrInfo);
963}
964
965
966SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
967{
968 /*
969 * Validate input.
970 */
971 RTErrInfoClear(pErrInfo);
972 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
973 AssertPtrReturn(phLdrMod, VERR_INVALID_POINTER);
974 *phLdrMod = NIL_RTLDRMOD;
975 AssertReturn(RTPathHavePath(pszFilename), VERR_INVALID_PARAMETER);
976
977 /*
978 * Add the default extension if it's missing.
979 */
980 if (!RTPathHasSuffix(pszFilename))
981 {
982 const char *pszSuff = RTLdrGetSuff();
983 size_t cchSuff = strlen(pszSuff);
984 size_t cchFilename = strlen(pszFilename);
985 char *psz = (char *)alloca(cchFilename + cchSuff + 1);
986 AssertReturn(psz, VERR_NO_TMP_MEMORY);
987 memcpy(psz, pszFilename, cchFilename);
988 memcpy(psz + cchFilename, pszSuff, cchSuff + 1);
989 pszFilename = psz;
990 }
991
992 /*
993 * Pass it on to the common library loader.
994 */
995 return supR3HardenedLdrLoadIt(pszFilename, phLdrMod, fFlags, pErrInfo);
996}
997
998
999SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
1000{
1001 LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p fFlags=%08x pErrInfo=%p\n", pszFilename, pszFilename, phLdrMod, fFlags, pErrInfo));
1002
1003 /*
1004 * Validate input.
1005 */
1006 RTErrInfoClear(pErrInfo);
1007 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
1008 *phLdrMod = NIL_RTLDRMOD;
1009 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1010 AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
1011
1012 /*
1013 * Check the filename.
1014 */
1015 size_t cchFilename = strlen(pszFilename);
1016 AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
1017
1018 const char *pszExt = "";
1019 size_t cchExt = 0;
1020 if (!RTPathHasSuffix(pszFilename))
1021 {
1022 pszExt = RTLdrGetSuff();
1023 cchExt = strlen(pszExt);
1024 }
1025
1026 /*
1027 * Construct the private arch path and check if the file exists.
1028 */
1029 char szPath[RTPATH_MAX];
1030 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchExt - cchFilename);
1031 AssertRCReturn(rc, rc);
1032
1033 char *psz = strchr(szPath, '\0');
1034 *psz++ = RTPATH_SLASH;
1035 memcpy(psz, pszFilename, cchFilename);
1036 psz += cchFilename;
1037 memcpy(psz, pszExt, cchExt + 1);
1038
1039 if (!RTPathExists(szPath))
1040 {
1041 LogRel(("SUPR3HardenedLdrLoadAppPriv: \"%s\" not found\n", szPath));
1042 return VERR_FILE_NOT_FOUND;
1043 }
1044
1045 /*
1046 * Pass it on to SUPR3HardenedLdrLoad.
1047 */
1048 rc = SUPR3HardenedLdrLoad(szPath, phLdrMod, fFlags, pErrInfo);
1049
1050 LogFlow(("SUPR3HardenedLdrLoadAppPriv: returns %Rrc\n", rc));
1051 return rc;
1052}
1053
1054
1055SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
1056{
1057 /*
1058 * Validate input.
1059 */
1060 RTErrInfoClear(pErrInfo);
1061 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
1062 *phLdrMod = NIL_RTLDRMOD;
1063 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1064 AssertReturn(RTPathStartsWithRoot(pszFilename), VERR_INVALID_PARAMETER);
1065
1066#ifdef VBOX_WITH_HARDENING
1067 /*
1068 * Verify the image file.
1069 */
1070 int rc = supR3HardenedVerifyFile(pszFilename, RTHCUINTPTR_MAX, true /*fMaybe3rdParty*/, pErrInfo);
1071 if (RT_FAILURE(rc))
1072 {
1073 if (!RTErrInfoIsSet(pErrInfo))
1074 LogRel(("supR3HardenedVerifyFile: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1075 return rc;
1076 }
1077#endif
1078
1079 /*
1080 * Try load it.
1081 */
1082 return RTLdrLoadEx(pszFilename, phLdrMod, RTLDRLOAD_FLAGS_LOCAL, pErrInfo);
1083}
1084
Note: See TracBrowser for help on using the repository browser.

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