VirtualBox

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

Last change on this file was 108724, checked in by vboxsync, 6 weeks ago

HostDrivers/Support: Make SUPR3 work on hosts where the page size is not known during compile time, bugref:10391

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