diff options
| author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2020-07-29 10:10:49 +0000 |
|---|---|---|
| committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2020-07-29 10:10:49 +0000 |
| commit | 011df67d3758f4830b93de62d48b072a6784a3ee (patch) | |
| tree | 4d82e683e5a8e9a460ff13c8c3f173305ea2075f /src/VBox/HostDrivers/Support/SUPLibLdr.cpp | |
| parent | 7cdf0c7454216b0e8fc2d2c67c7c33b60653f344 (diff) | |
| download | VirtualBox-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.cpp | 649 |
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"); |
