summaryrefslogtreecommitdiff
path: root/src/VBox/HostDrivers/Support/SUPLibLdr.cpp
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2020-07-29 10:10:49 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2020-07-29 10:10:49 +0000
commit011df67d3758f4830b93de62d48b072a6784a3ee (patch)
tree4d82e683e5a8e9a460ff13c8c3f173305ea2075f /src/VBox/HostDrivers/Support/SUPLibLdr.cpp
parent7cdf0c7454216b0e8fc2d2c67c7c33b60653f344 (diff)
downloadVirtualBox-svn-011df67d3758f4830b93de62d48b072a6784a3ee.tar.gz
SUP,*: Some changes to the SUP_IOCTL_LDR_OPEN and SUP_IOCTL_LDR_LOAD interfaces adding memory protection regions for better W^X 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. bugref:9801
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@85507 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/HostDrivers/Support/SUPLibLdr.cpp')
-rw-r--r--src/VBox/HostDrivers/Support/SUPLibLdr.cpp649
1 files changed, 441 insertions, 208 deletions
diff --git a/src/VBox/HostDrivers/Support/SUPLibLdr.cpp b/src/VBox/HostDrivers/Support/SUPLibLdr.cpp
index b161e51508a..c3a6166faf2 100644
--- a/src/VBox/HostDrivers/Support/SUPLibLdr.cpp
+++ b/src/VBox/HostDrivers/Support/SUPLibLdr.cpp
@@ -334,6 +334,363 @@ static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char
}
+/** Argument package for supLoadModuleCompileSegmentsCB. */
+typedef struct SUPLDRCOMPSEGTABARGS
+{
+ uint32_t uStartRva;
+ uint32_t uEndRva;
+ uint32_t fProt;
+ uint32_t iSegs;
+ uint32_t cSegsAlloc;
+ PSUPLDRSEG paSegs;
+ PRTERRINFO pErrInfo;
+} SUPLDRCOMPSEGTABARGS, *PSUPLDRCOMPSEGTABARGS;
+
+/**
+ * @callback_method_impl{FNRTLDRENUMSEGS,
+ * Compile list of segments with the same memory protection.}
+ */
+static DECLCALLBACK(int) supLoadModuleCompileSegmentsCB(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ PSUPLDRCOMPSEGTABARGS pArgs = (PSUPLDRCOMPSEGTABARGS)pvUser;
+ AssertCompile(RTMEM_PROT_READ == SUPLDR_PROT_READ);
+ AssertCompile(RTMEM_PROT_WRITE == SUPLDR_PROT_WRITE);
+ AssertCompile(RTMEM_PROT_EXEC == SUPLDR_PROT_EXEC);
+ RT_NOREF(hLdrMod);
+
+ /* Ignore segments not part of the loaded image. */
+ if (pSeg->RVA == NIL_RTLDRADDR || pSeg->cbMapped == 0)
+ return VINF_SUCCESS;
+
+ /* We currently ASSUME that all relevant segments are in ascending RVA order. */
+ AssertReturn(pSeg->RVA >= pArgs->uEndRva,
+ RTERRINFO_LOG_REL_SET_F(pArgs->pErrInfo, VERR_BAD_EXE_FORMAT, "Out of order segment: %p LB %#zx #%.*s",
+ pSeg->RVA, pSeg->cb, pSeg->cchName, pSeg->pszName));
+
+ /* We ASSUME the cbMapped field is implemented. */
+ AssertReturn(pSeg->cbMapped != NIL_RTLDRADDR, VERR_INTERNAL_ERROR_2);
+ AssertReturn(pSeg->cbMapped < _1G, VERR_INTERNAL_ERROR_4);
+ uint32_t cbMapped = (uint32_t)pSeg->cbMapped;
+ AssertReturn(pSeg->RVA < _1G, VERR_INTERNAL_ERROR_3);
+ uint32_t uRvaSeg = (uint32_t)pSeg->RVA;
+ Log2(("supLoadModuleCompileSegmentsCB: %RTptr/%RTptr LB %RTptr prot %#x %s\n",
+ pSeg->LinkAddress, pSeg->RVA, pSeg->cbMapped, pSeg->fProt, pSeg->pszName));
+
+ /*
+ * If the protection is the same as the previous segment,
+ * just update uEndRva and continue.
+ */
+ uint32_t fProt = pSeg->fProt;
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ if (fProt & RTMEM_PROT_EXEC)
+ fProt |= fProt & RTMEM_PROT_READ;
+#endif
+ if (pSeg->fProt == pArgs->fProt)
+ {
+ pArgs->uEndRva = uRvaSeg + cbMapped;
+ Log2(("supLoadModuleCompileSegmentsCB: -> merged\n"));
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * The protection differs, so commit current segment and start a new one.
+ * However, if the new segment and old segment share a page, this becomes
+ * a little more complicated...
+ */
+ if (pArgs->uStartRva < pArgs->uEndRva)
+ {
+ if (((pArgs->uEndRva - 1) >> PAGE_SHIFT) != (uRvaSeg >> PAGE_SHIFT))
+ {
+ /* No common page, so make the new segment start on a page boundrary. */
+ cbMapped += uRvaSeg & PAGE_OFFSET_MASK;
+ uRvaSeg &= ~(uint32_t)PAGE_OFFSET_MASK;
+ Assert(pArgs->uEndRva <= uRvaSeg);
+ Log2(("supLoadModuleCompileSegmentsCB: -> new, no common\n"));
+ }
+ else if ((fProt & pArgs->fProt) == fProt)
+ {
+ /* The current segment includes the memory protections of the
+ previous, so include the common page in it: */
+ uint32_t const cbCommon = PAGE_SIZE - (uRvaSeg & PAGE_OFFSET_MASK);
+ if (cbCommon >= cbMapped)
+ {
+ pArgs->uEndRva = uRvaSeg + cbMapped;
+ Log2(("supLoadModuleCompileSegmentsCB: -> merge, %#x common, upgrading prot to %#x\n", cbCommon, pArgs->fProt));
+ return VINF_SUCCESS; /* New segment was smaller than a page. */
+ }
+ cbMapped -= cbCommon;
+ uRvaSeg += cbCommon;
+ Assert(pArgs->uEndRva <= uRvaSeg);
+ Log2(("supLoadModuleCompileSegmentsCB: -> new, %#x common into previous\n", cbCommon));
+ }
+ else if ((fProt & pArgs->fProt) == pArgs->fProt)
+ {
+ /* The new segment includes the memory protections of the
+ previous, so include the common page in it: */
+ cbMapped += uRvaSeg & PAGE_OFFSET_MASK;
+ uRvaSeg &= ~(uint32_t)PAGE_OFFSET_MASK;
+ if (uRvaSeg == pArgs->uStartRva)
+ {
+ pArgs->fProt = fProt;
+ pArgs->uEndRva = uRvaSeg + cbMapped;
+ Log2(("supLoadModuleCompileSegmentsCB: -> upgrade current protection\n"));
+ return VINF_SUCCESS; /* Current segment was smaller than a page. */
+ }
+ Log2(("supLoadModuleCompileSegmentsCB: -> new, %#x common into new\n", (uint32_t)(pSeg->RVA & PAGE_OFFSET_MASK)));
+ }
+ else
+ {
+ /* Create a new segment for the common page with the combined protection. */
+ Log2(("supLoadModuleCompileSegmentsCB: -> its complicated...\n"));
+ pArgs->uEndRva &= ~(uint32_t)PAGE_OFFSET_MASK;
+ if (pArgs->uEndRva > pArgs->uStartRva)
+ {
+ Log2(("supLoadModuleCompileSegmentsCB: SUP Seg #%u: %#x LB %#x prot %#x\n",
+ pArgs->iSegs, pArgs->uStartRva, pArgs->uEndRva - pArgs->uStartRva, pArgs->fProt));
+ if (pArgs->paSegs)
+ {
+ AssertReturn(pArgs->iSegs < pArgs->cSegsAlloc, VERR_INTERNAL_ERROR_5);
+ pArgs->paSegs[pArgs->iSegs].off = pArgs->uStartRva;
+ pArgs->paSegs[pArgs->iSegs].cb = pArgs->uEndRva - pArgs->uStartRva;
+ pArgs->paSegs[pArgs->iSegs].fProt = pArgs->fProt;
+ }
+ pArgs->iSegs++;
+ pArgs->uStartRva = pArgs->uEndRva;
+ }
+ pArgs->fProt |= fProt;
+
+ uint32_t const cbCommon = PAGE_SIZE - (uRvaSeg & PAGE_OFFSET_MASK);
+ if (cbCommon <= cbMapped)
+ {
+ fProt |= pArgs->fProt;
+ pArgs->uEndRva = uRvaSeg + cbMapped;
+ return VINF_SUCCESS; /* New segment was smaller than a page. */
+ }
+ cbMapped -= cbCommon;
+ uRvaSeg += cbCommon;
+ Assert(uRvaSeg - pArgs->uStartRva == PAGE_SIZE);
+ }
+
+ /* The current segment should end where the new one starts, no gaps. */
+ pArgs->uEndRva = uRvaSeg;
+
+ /* Emit the current segment */
+ Log2(("supLoadModuleCompileSegmentsCB: SUP Seg #%u: %#x LB %#x prot %#x\n",
+ pArgs->iSegs, pArgs->uStartRva, pArgs->uEndRva - pArgs->uStartRva, pArgs->fProt));
+ if (pArgs->paSegs)
+ {
+ AssertReturn(pArgs->iSegs < pArgs->cSegsAlloc, VERR_INTERNAL_ERROR_5);
+ pArgs->paSegs[pArgs->iSegs].off = pArgs->uStartRva;
+ pArgs->paSegs[pArgs->iSegs].cb = pArgs->uEndRva - pArgs->uStartRva;
+ pArgs->paSegs[pArgs->iSegs].fProt = pArgs->fProt;
+ }
+ pArgs->iSegs++;
+ }
+ /* else: current segment is empty */
+
+ /* Start the new segment. */
+ Assert(!(uRvaSeg & PAGE_OFFSET_MASK));
+ pArgs->fProt = fProt;
+ pArgs->uStartRva = uRvaSeg;
+ pArgs->uEndRva = uRvaSeg + cbMapped;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for supLoadModule().
+ */
+static int supLoadModuleInner(RTLDRMOD hLdrMod, PSUPLDRLOAD pLoadReq, uint32_t cbImageWithEverything,
+ RTR0PTR uImageBase, size_t cbImage, const char *pszModule, const char *pszFilename,
+ bool fNativeLoader, bool fIsVMMR0, const char *pszSrvReqHandler,
+ uint32_t offSymTab, uint32_t cSymbols,
+ uint32_t offStrTab, size_t cbStrTab,
+ uint32_t offSegTab, uint32_t cSegments,
+ PRTERRINFO pErrInfo)
+{
+ /*
+ * Get the image bits.
+ */
+ SUPLDRRESIMPARGS Args = { pszModule, pErrInfo };
+ int rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase, supLoadModuleResolveImport, &Args);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("SUP: RTLdrGetBits failed for %s (%s). rc=%Rrc\n", pszModule, pszFilename, rc));
+ if (!RTErrInfoIsSet(pErrInfo))
+ RTErrInfoSetF(pErrInfo, rc, "RTLdrGetBits failed");
+ return rc;
+ }
+
+ /*
+ * Get the entry points.
+ */
+ RTUINTPTR VMMR0EntryFast = 0;
+ RTUINTPTR VMMR0EntryEx = 0;
+ RTUINTPTR SrvReqHandler = 0;
+ RTUINTPTR ModuleInit = 0;
+ RTUINTPTR ModuleTerm = 0;
+ const char *pszEp = NULL;
+ if (fIsVMMR0)
+ {
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
+ UINT32_MAX, pszEp = "VMMR0EntryFast", &VMMR0EntryFast);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
+ UINT32_MAX, pszEp = "VMMR0EntryEx", &VMMR0EntryEx);
+ }
+ else if (pszSrvReqHandler)
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
+ UINT32_MAX, pszEp = pszSrvReqHandler, &SrvReqHandler);
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
+ UINT32_MAX, pszEp = "ModuleInit", &ModuleInit);
+ if (RT_FAILURE(rc2))
+ ModuleInit = 0;
+
+ rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], uImageBase,
+ UINT32_MAX, pszEp = "ModuleTerm", &ModuleTerm);
+ if (RT_FAILURE(rc2))
+ ModuleTerm = 0;
+ }
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("SUP: Failed to get entry point '%s' for %s (%s) rc=%Rrc\n", pszEp, pszModule, pszFilename, rc));
+ return RTErrInfoSetF(pErrInfo, rc, "Failed to resolve entry point '%s'", pszEp);
+ }
+
+ /*
+ * Create the symbol and string tables.
+ */
+ SUPLDRCREATETABSARGS CreateArgs;
+ CreateArgs.cbImage = cbImage;
+ CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab];
+ CreateArgs.pszBase = (char *)&pLoadReq->u.In.abImage[offStrTab];
+ CreateArgs.psz = CreateArgs.pszBase;
+ rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("SUP: RTLdrEnumSymbols failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
+ return RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #2 failed");
+ }
+ AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= cbStrTab);
+ AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= cSymbols);
+
+ /*
+ * Create the segment table.
+ */
+ SUPLDRCOMPSEGTABARGS SegArgs;
+ SegArgs.uStartRva = 0;
+ SegArgs.uEndRva = 0;
+ SegArgs.fProt = RTMEM_PROT_READ;
+ SegArgs.iSegs = 0;
+ SegArgs.cSegsAlloc = cSegments;
+ SegArgs.paSegs = (PSUPLDRSEG)&pLoadReq->u.In.abImage[offSegTab];
+ SegArgs.pErrInfo = pErrInfo;
+ rc = RTLdrEnumSegments(hLdrMod, supLoadModuleCompileSegmentsCB, &SegArgs);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("SUP: RTLdrEnumSegments failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
+ return RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSegments #2 failed");
+ }
+ SegArgs.uEndRva = cbImage;
+ if (SegArgs.uEndRva > SegArgs.uStartRva)
+ {
+ SegArgs.paSegs[SegArgs.iSegs].off = SegArgs.uStartRva;
+ SegArgs.paSegs[SegArgs.iSegs].cb = SegArgs.uEndRva - SegArgs.uStartRva;
+ SegArgs.paSegs[SegArgs.iSegs].fProt = SegArgs.fProt;
+ SegArgs.iSegs++;
+ }
+ for (uint32_t i = 0; i < SegArgs.iSegs; i++)
+ LogRel(("SUP: seg #%u: %c%c%c %#010RX32 LB %#010RX32\n", i, /** @todo LogRel2 */
+ SegArgs.paSegs[i].fProt & SUPLDR_PROT_READ ? 'R' : ' ',
+ SegArgs.paSegs[i].fProt & SUPLDR_PROT_WRITE ? 'W' : ' ',
+ SegArgs.paSegs[i].fProt & SUPLDR_PROT_EXEC ? 'X' : ' ',
+ SegArgs.paSegs[i].off, SegArgs.paSegs[i].cb));
+ AssertRelease(SegArgs.iSegs == cSegments);
+ AssertRelease(SegArgs.cSegsAlloc == cSegments);
+
+ /*
+ * Upload the image.
+ */
+ pLoadReq->Hdr.u32Cookie = g_u32Cookie;
+ pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImageWithEverything);
+ pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
+ pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
+ pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
+
+ pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
+ pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
+ if (fIsVMMR0)
+ {
+ pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0 = uImageBase;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
+ }
+ else if (pszSrvReqHandler)
+ {
+ pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
+ pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
+ pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
+ pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
+ pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
+ }
+ else
+ pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
+ pLoadReq->u.In.offStrTab = offStrTab;
+ pLoadReq->u.In.cbStrTab = (uint32_t)cbStrTab;
+ AssertRelease(pLoadReq->u.In.cbStrTab == cbStrTab);
+ pLoadReq->u.In.cbImageBits = (uint32_t)cbImage;
+ pLoadReq->u.In.offSymbols = offSymTab;
+ pLoadReq->u.In.cSymbols = cSymbols;
+ pLoadReq->u.In.offSegments = offSegTab;
+ pLoadReq->u.In.cSegments = cSegments;
+ pLoadReq->u.In.cbImageWithEverything = cbImageWithEverything;
+ pLoadReq->u.In.pvImageBase = uImageBase;
+ if (!g_uSupFakeMode)
+ {
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything));
+ if (RT_SUCCESS(rc))
+ rc = pLoadReq->Hdr.rc;
+ else
+ LogRel(("SUP: SUP_IOCTL_LDR_LOAD ioctl for %s (%s) failed rc=%Rrc\n", pszModule, pszFilename, rc));
+ }
+ else
+ rc = VINF_SUCCESS;
+ if ( RT_SUCCESS(rc)
+ || rc == VERR_ALREADY_LOADED /* A competing process. */
+ )
+ {
+ LogRel(("SUP: Loaded %s (%s) at %#RKv - ModuleInit at %RKv and ModuleTerm at %RKv%s\n",
+ pszModule, pszFilename, uImageBase, (RTR0PTR)ModuleInit, (RTR0PTR)ModuleTerm,
+ fNativeLoader ? " using the native ring-0 loader" : ""));
+ if (fIsVMMR0)
+ {
+ g_pvVMMR0 = uImageBase;
+ LogRel(("SUP: VMMR0EntryEx located at %RKv and VMMR0EntryFast at %RKv\n", (RTR0PTR)VMMR0EntryEx, (RTR0PTR)VMMR0EntryFast));
+ }
+#ifdef RT_OS_WINDOWS
+ LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, uImageBase));
+#endif
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Failed, bail out.
+ */
+ LogRel(("SUP: Loading failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
+ if ( pLoadReq->u.Out.uErrorMagic == SUPLDRLOAD_ERROR_MAGIC
+ && pLoadReq->u.Out.szError[0] != '\0')
+ {
+ LogRel(("SUP: %s\n", pLoadReq->u.Out.szError));
+ return RTErrInfoSet(pErrInfo, rc, pLoadReq->u.Out.szError);
+ }
+ return RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_LOAD failed");
+}
+
+
/**
* Worker for SUPR3LoadModule().
*
@@ -356,6 +713,7 @@ static int supLoadModule(const char *pszFilename, const char *pszModule, const c
AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
+ /** @todo abspath it right into SUPLDROPEN */
AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
char szAbsFilename[RT_SIZEOFMEMB(SUPLDROPEN, u.In.szFilename)];
rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
@@ -371,8 +729,8 @@ static int supLoadModule(const char *pszFilename, const char *pszModule, const c
* Open image file and figure its size.
*/
RTLDRMOD hLdrMod;
- rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_HOST, &hLdrMod);
- if (!RT_SUCCESS(rc))
+ rc = RTLdrOpenEx(pszFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod, pErrInfo);
+ if (RT_FAILURE(rc))
{
LogRel(("SUP: RTLdrOpen failed for %s (%s) %Rrc\n", pszModule, pszFilename, rc));
return rc;
@@ -385,230 +743,105 @@ static int supLoadModule(const char *pszFilename, const char *pszModule, const c
rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
if (RT_SUCCESS(rc))
{
- const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
- const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
- const uint32_t cbImageWithTabs = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
-
/*
- * Open the R0 image.
+ * Figure out the number of segments needed first.
*/
- SUPLDROPEN OpenReq;
- OpenReq.Hdr.u32Cookie = g_u32Cookie;
- OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
- OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
- OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
- OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
- OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
- OpenReq.u.In.cbImageWithTabs = cbImageWithTabs;
- OpenReq.u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
- strcpy(OpenReq.u.In.szName, pszModule);
- strcpy(OpenReq.u.In.szFilename, pszFilename);
- if (!g_uSupFakeMode)
- {
- rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
- if (RT_SUCCESS(rc))
- rc = OpenReq.Hdr.rc;
- }
- else
- {
- OpenReq.u.Out.fNeedsLoading = true;
- OpenReq.u.Out.pvImageBase = 0xef423420;
- }
- *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
- if ( RT_SUCCESS(rc)
- && OpenReq.u.Out.fNeedsLoading)
+ SUPLDRCOMPSEGTABARGS SegArgs;
+ SegArgs.uStartRva = 0;
+ SegArgs.uEndRva = 0;
+ SegArgs.fProt = RTMEM_PROT_READ;
+ SegArgs.iSegs = 0;
+ SegArgs.cSegsAlloc = 0;
+ SegArgs.paSegs = NULL;
+ SegArgs.pErrInfo = pErrInfo;
+ rc = RTLdrEnumSegments(hLdrMod, supLoadModuleCompileSegmentsCB, &SegArgs);
+ if (RT_SUCCESS(rc))
{
+ Assert(SegArgs.uEndRva <= RTLdrSize(hLdrMod));
+ SegArgs.uEndRva = RTLdrSize(hLdrMod);
+ if (SegArgs.uEndRva > SegArgs.uStartRva)
+ SegArgs.iSegs++;
+
+ const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
+ const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
+ const uint32_t offSegTab = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
+ const uint32_t cbImageWithEverything = RT_ALIGN_32(offSegTab + sizeof(SUPLDRSEG) * SegArgs.iSegs, 8);
+
/*
- * We need to load it.
- * Allocate memory for the image bits.
+ * Open the R0 image.
*/
- PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
- if (pLoadReq)
+ SUPLDROPEN OpenReq;
+ OpenReq.Hdr.u32Cookie = g_u32Cookie;
+ OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
+ OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
+ OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
+ OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
+ OpenReq.u.In.cbImageWithEverything = cbImageWithEverything;
+ OpenReq.u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
+ strcpy(OpenReq.u.In.szName, pszModule);
+ strcpy(OpenReq.u.In.szFilename, pszFilename);
+ if (!g_uSupFakeMode)
+ {
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = OpenReq.Hdr.rc;
+ }
+ else
+ {
+ OpenReq.u.Out.fNeedsLoading = true;
+ OpenReq.u.Out.pvImageBase = 0xef423420;
+ }
+ *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
+ if ( RT_SUCCESS(rc)
+ && OpenReq.u.Out.fNeedsLoading)
{
/*
- * Get the image bits.
+ * We need to load it.
+ *
+ * Allocate the request and pass it to an inner work function
+ * that populates it and sends it off to the driver.
*/
-
- SUPLDRRESIMPARGS Args = { pszModule, pErrInfo };
- rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
- supLoadModuleResolveImport, &Args);
-
- if (RT_SUCCESS(rc))
+ const uint32_t cbLoadReq = SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything);
+ PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(cbLoadReq);
+ if (pLoadReq)
{
- /*
- * Get the entry points.
- */
- RTUINTPTR VMMR0EntryFast = 0;
- RTUINTPTR VMMR0EntryEx = 0;
- RTUINTPTR SrvReqHandler = 0;
- RTUINTPTR ModuleInit = 0;
- RTUINTPTR ModuleTerm = 0;
- const char *pszEp = NULL;
- if (fIsVMMR0)
- {
- rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
- UINT32_MAX, pszEp = "VMMR0EntryFast", &VMMR0EntryFast);
- if (RT_SUCCESS(rc))
- rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
- UINT32_MAX, pszEp = "VMMR0EntryEx", &VMMR0EntryEx);
- }
- else if (pszSrvReqHandler)
- rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
- UINT32_MAX, pszEp = pszSrvReqHandler, &SrvReqHandler);
- if (RT_SUCCESS(rc))
- {
- int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
- UINT32_MAX, pszEp = "ModuleInit", &ModuleInit);
- if (RT_FAILURE(rc2))
- ModuleInit = 0;
-
- rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
- UINT32_MAX, pszEp = "ModuleTerm", &ModuleTerm);
- if (RT_FAILURE(rc2))
- ModuleTerm = 0;
- }
- if (RT_SUCCESS(rc))
- {
- /*
- * Create the symbol and string tables.
- */
- SUPLDRCREATETABSARGS CreateArgs;
- CreateArgs.cbImage = CalcArgs.cbImage;
- CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab];
- CreateArgs.pszBase = (char *)&pLoadReq->u.In.abImage[offStrTab];
- CreateArgs.psz = CreateArgs.pszBase;
- rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
- if (RT_SUCCESS(rc))
- {
- AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
- AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= CalcArgs.cSymbols);
-
- /*
- * Upload the image.
- */
- pLoadReq->Hdr.u32Cookie = g_u32Cookie;
- pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
- pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImageWithTabs);
- pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
- pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
- pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
-
- pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
- pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
- if (fIsVMMR0)
- {
- pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
- pLoadReq->u.In.EP.VMMR0.pvVMMR0 = OpenReq.u.Out.pvImageBase;
- pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
- pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
- }
- else if (pszSrvReqHandler)
- {
- pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
- pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
- pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
- pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
- pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
- }
- else
- pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
- pLoadReq->u.In.offStrTab = offStrTab;
- pLoadReq->u.In.cbStrTab = (uint32_t)CalcArgs.cbStrings;
- AssertRelease(pLoadReq->u.In.cbStrTab == CalcArgs.cbStrings);
- pLoadReq->u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
- pLoadReq->u.In.offSymbols = offSymTab;
- pLoadReq->u.In.cSymbols = CalcArgs.cSymbols;
- pLoadReq->u.In.cbImageWithTabs = cbImageWithTabs;
- pLoadReq->u.In.pvImageBase = OpenReq.u.Out.pvImageBase;
- if (!g_uSupFakeMode)
- {
- rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
- if (RT_SUCCESS(rc))
- rc = pLoadReq->Hdr.rc;
- else
- LogRel(("SUP: SUP_IOCTL_LDR_LOAD ioctl for %s (%s) failed rc=%Rrc\n", pszModule, pszFilename, rc));
- }
- else
- rc = VINF_SUCCESS;
- if ( RT_SUCCESS(rc)
- || rc == VERR_ALREADY_LOADED /* A competing process. */
- )
- {
- LogRel(("SUP: Loaded %s (%s) at %#RKv - ModuleInit at %RKv and ModuleTerm at %RKv%s\n",
- pszModule, pszFilename, OpenReq.u.Out.pvImageBase, (RTR0PTR)ModuleInit, (RTR0PTR)ModuleTerm,
- OpenReq.u.Out.fNativeLoader ? " using the native ring-0 loader" : ""));
- if (fIsVMMR0)
- {
- g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
- LogRel(("SUP: VMMR0EntryEx located at %RKv and VMMR0EntryFast at %RKv\n", (RTR0PTR)VMMR0EntryEx, (RTR0PTR)VMMR0EntryFast));
- }
-#ifdef RT_OS_WINDOWS
- LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, OpenReq.u.Out.pvImageBase));
-#endif
-
- RTMemTmpFree(pLoadReq);
- RTLdrClose(hLdrMod);
- return VINF_SUCCESS;
- }
-
- /*
- * Failed, bail out.
- */
- LogRel(("SUP: Loading failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
- if ( pLoadReq->u.Out.uErrorMagic == SUPLDRLOAD_ERROR_MAGIC
- && pLoadReq->u.Out.szError[0] != '\0')
- {
- LogRel(("SUP: %s\n", pLoadReq->u.Out.szError));
- RTErrInfoSet(pErrInfo, rc, pLoadReq->u.Out.szError);
- }
- else
- RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_LOAD failed");
- }
- else
- {
- LogRel(("SUP: RTLdrEnumSymbols failed for %s (%s) rc=%Rrc\n", pszModule, pszFilename, rc));
- RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #2 failed");
- }
- }
- else
- {
- LogRel(("SUP: Failed to get entry point '%s' for %s (%s) rc=%Rrc\n", pszEp, pszModule, pszFilename, rc));
- RTErrInfoSetF(pErrInfo, rc, "Failed to resolve entry point '%s'", pszEp);
- }
+ rc = supLoadModuleInner(hLdrMod, pLoadReq, cbImageWithEverything, OpenReq.u.Out.pvImageBase, CalcArgs.cbImage,
+ pszModule, pszFilename, OpenReq.u.Out.fNativeLoader, fIsVMMR0, pszSrvReqHandler,
+ offSymTab, CalcArgs.cSymbols,
+ offStrTab, CalcArgs.cbStrings,
+ offSegTab, SegArgs.iSegs,
+ pErrInfo);
+ RTMemTmpFree(pLoadReq);
}
else
{
- LogRel(("SUP: RTLdrGetBits failed for %s (%s). rc=%Rrc\n", pszModule, pszFilename, rc));
- if (!RTErrInfoIsSet(pErrInfo))
- RTErrInfoSetF(pErrInfo, rc, "RTLdrGetBits failed");
+ AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything)));
+ rc = RTErrInfoSetF(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %u bytes for the load request",
+ SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithEverything));
}
- RTMemTmpFree(pLoadReq);
}
- else
+ /*
+ * Already loaded?
+ */
+ else if (RT_SUCCESS(rc))
{
- AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs)));
- rc = VERR_NO_TMP_MEMORY;
- RTErrInfoSetF(pErrInfo, rc, "Failed to allocate %u bytes for the load request", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
- }
- }
- /*
- * Already loaded?
- */
- else if (RT_SUCCESS(rc))
- {
- if (fIsVMMR0)
- g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
- LogRel(("SUP: Opened %s (%s) at %#RKv%s.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase,
- OpenReq.u.Out.fNativeLoader ? " loaded by the native ring-0 loader" : ""));
+ if (fIsVMMR0)
+ g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
+ LogRel(("SUP: Opened %s (%s) at %#RKv%s.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase,
+ OpenReq.u.Out.fNativeLoader ? " loaded by the native ring-0 loader" : ""));
#ifdef RT_OS_WINDOWS
- LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, OpenReq.u.Out.pvImageBase));
+ LogRel(("SUP: windbg> .reload /f %s=%#RKv\n", pszFilename, OpenReq.u.Out.pvImageBase));
#endif
+ }
+ /*
+ * No, failed.
+ */
+ else
+ RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_OPEN failed");
}
- /*
- * No, failed.
- */
- else
- RTErrInfoSet(pErrInfo, rc, "SUP_IOCTL_LDR_OPEN failed");
+ else if (!RTErrInfoIsSet(pErrInfo) && pErrInfo)
+ RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSegments #1 failed");
}
else
RTErrInfoSetF(pErrInfo, rc, "RTLdrEnumSymbols #1 failed");