SUPLibLdr.cpp revision 98b3fe217f35498ace90d9b63a8298c0b6353c2c
/* $Id$ */
/** @file
* VirtualBox Support Library - Loader related bits.
*/
/*
* Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/** @page pg_sup SUP - The Support Library
*
* The support library is responsible for providing facilities to load
* VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
* code, to pin down physical memory, and more.
*
* The VMM Host Ring-0 code can be combined in the support driver if
* permitted by kernel module license policies. If it is not combined
* it will be externalized in a .r0 module that will be loaded using
* the IPRT loader.
*
* The Ring-0 calling is done thru a generic SUP interface which will
* transfer an argument set and call a predefined entry point in the Host
* VMM Ring-0 code.
*
* See @ref grp_sup "SUP - Support APIs" for API details.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_SUP
#include "SUPDrvIOC.h"
#include "SUPLibInternal.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** R0 VMM module name. */
#define VMMR0_NAME "VMMR0"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef FNCALLVMMR0 *PFNCALLVMMR0;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** VMMR0 Load Address. */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase);
static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo)
{
/*
* Check that the module can be trusted.
*/
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
}
return rc;
}
const char *pszSrvReqHandler, void **ppvImageBase)
{
/*
* Check that the module can be trusted.
*/
if (RT_SUCCESS(rc))
else
return rc;
}
/**
* Resolve an external symbol during RTLdrGetBits().
*
* @returns VBox status code.
* @param hLdrMod The loader module handle.
* @param pszModule Module name.
* @param pszSymbol Symbol name, NULL if uSymbol should be used.
* @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
* @param pValue Where to store the symbol value (address).
* @param pvUser User argument.
*/
{
/*
* Only SUPR0 and VMMR0.r0
*/
if ( pszModule
&& *pszModule
{
AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pvUser, pszModule));
return VERR_SYMBOL_NOT_FOUND;
}
/*
* No ordinals.
*/
if (pszSymbol < (const char*)0x10000)
{
return VERR_SYMBOL_NOT_FOUND;
}
/*
* Lookup symbol.
*/
/** @todo is this actually used??? */
/* skip the 64-bit ELF import prefix first. */
/*
* Check the VMMR0.r0 module if loaded.
*/
/** @todo call the SUPR3LoadModule caller.... */
/** @todo proper reference counting and such. */
if (g_pvVMMR0 != NIL_RTR0PTR)
{
void *pvValue;
{
return VINF_SUCCESS;
}
}
/* iterate the function table. */
while (c-- > 0)
{
{
return VINF_SUCCESS;
}
pFunc++;
}
/*
* The GIP.
*/
if ( pszSymbol
)
{
return VINF_SUCCESS;
}
/*
* Symbols that are undefined by convention.
*/
#ifdef RT_OS_SOLARIS
static const char * const s_apszConvSyms[] =
{
"", "mod_getctl",
"", "mod_install",
"", "mod_remove",
"", "mod_info",
"", "mod_miscops",
};
{
{
return VINF_SUCCESS;
}
}
#endif
/*
* Despair.
*/
while (c-- > 0)
{
pFunc++;
}
if (g_uSupFakeMode)
{
*pValue = 0xdeadbeef;
return VINF_SUCCESS;
}
return VERR_SYMBOL_NOT_FOUND;
}
/** Argument package for supLoadModuleCalcSizeCB. */
typedef struct SUPLDRCALCSIZEARGS
{
/**
* Callback used to calculate the image size.
* @return VINF_SUCCESS
*/
static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
{
&& *pszSymbol
{
}
return VINF_SUCCESS;
}
/** Argument package for supLoadModuleCreateTabsCB. */
typedef struct SUPLDRCREATETABSARGS
{
char *pszBase;
char *psz;
/**
* Callback used to calculate the image size.
* @return VINF_SUCCESS
*/
static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
{
&& *pszSymbol
{
}
return VINF_SUCCESS;
}
/**
* Worker for SUPR3LoadModule().
*
* @returns VBox status code.
* @param pszFilename Name of the VMMR0 image file
*/
static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase)
{
int rc;
/*
* Validate input.
*/
if (RT_FAILURE(rc))
return rc;
*ppvImageBase = NULL;
/*
* Open image file and figure its size.
*/
if (!RT_SUCCESS(rc))
{
return rc;
}
if (RT_SUCCESS(rc))
{
/*
* Open the R0 image.
*/
if (!g_uSupFakeMode)
{
if (RT_SUCCESS(rc))
}
else
{
}
if ( RT_SUCCESS(rc)
{
/*
* We need to load it.
* Allocate memory for the image bits.
*/
if (pLoadReq)
{
/*
* Get the image bits.
*/
supLoadModuleResolveImport, (void *)pszModule);
if (RT_SUCCESS(rc))
{
/*
* Get the entry points.
*/
RTUINTPTR VMMR0EntryInt = 0;
RTUINTPTR VMMR0EntryFast = 0;
RTUINTPTR VMMR0EntryEx = 0;
RTUINTPTR SrvReqHandler = 0;
RTUINTPTR ModuleInit = 0;
RTUINTPTR ModuleTerm = 0;
if (fIsVMMR0)
{
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
if (RT_SUCCESS(rc))
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
if (RT_SUCCESS(rc))
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
}
else if (pszSrvReqHandler)
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, pszSrvReqHandler, &SrvReqHandler);
if (RT_SUCCESS(rc))
{
int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
if (RT_FAILURE(rc2))
ModuleInit = 0;
rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
if (RT_FAILURE(rc2))
ModuleTerm = 0;
}
if (RT_SUCCESS(rc))
{
/*
* Create the symbol and string tables.
*/
if (RT_SUCCESS(rc))
{
AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= CalcArgs.cSymbols);
/*
* Upload the image.
*/
if (fIsVMMR0)
{
}
else if (pszSrvReqHandler)
{
}
else
if (!g_uSupFakeMode)
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
if (RT_SUCCESS(rc))
else
}
else
rc = VINF_SUCCESS;
if ( RT_SUCCESS(rc)
)
{
LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr%s\n",
if (fIsVMMR0)
{
LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
}
#ifdef RT_OS_WINDOWS
#endif
return VINF_SUCCESS;
}
else
}
else
}
else
}
else
}
else
{
AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs)));
}
}
else if (RT_SUCCESS(rc))
{
if (fIsVMMR0)
#ifdef RT_OS_WINDOWS
#endif
}
}
return rc;
}
{
/* fake */
if (RT_UNLIKELY(g_uSupFakeMode))
{
return VINF_SUCCESS;
}
/*
* Free the requested module.
*/
if (RT_SUCCESS(rc))
if ( RT_SUCCESS(rc)
return rc;
}
{
/* fake */
if (RT_UNLIKELY(g_uSupFakeMode))
{
return VINF_SUCCESS;
}
/*
* Do ioctl.
*/
return VERR_SYMBOL_NOT_FOUND;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
return rc;
}
{
void *pvImageBase;
}
SUPR3DECL(int) SUPR3UnloadVMM(void)
{
return SUPR3FreeModule((void*)g_pvVMMR0);
}
/**
* Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
*
* @returns iprt status code.
* @param pszFilename The full file name.
* @param phLdrMod Where to store the handle to the loaded module.
* @param fFlags See RTLDFLAGS_.
* @param pErrInfo Where to return extended error information.
* Optional.
*
*/
static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
{
#ifdef VBOX_WITH_HARDENING
/*
* Verify the image file.
*/
if (RT_FAILURE(rc))
{
}
#endif
/*
* Try load it.
*/
}
SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
{
/*
* Validate input.
*/
*phLdrMod = NIL_RTLDRMOD;
/*
* Add the default extension if it's missing.
*/
if (!RTPathHasSuffix(pszFilename))
{
const char *pszSuff = RTLdrGetSuff();
pszFilename = psz;
}
/*
* Pass it on to the common library loader.
*/
}
SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
{
LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p fFlags=%08x pErrInfo=%p\n", pszFilename, pszFilename, phLdrMod, fFlags, pErrInfo));
/*
* Validate input.
*/
*phLdrMod = NIL_RTLDRMOD;
/*
* Check the filename.
*/
AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
const char *pszExt = "";
if (!RTPathHasSuffix(pszFilename))
{
pszExt = RTLdrGetSuff();
}
/*
* Construct the private arch path and check if the file exists.
*/
char szPath[RTPATH_MAX];
*psz++ = RTPATH_SLASH;
psz += cchFilename;
if (!RTPathExists(szPath))
{
return VERR_FILE_NOT_FOUND;
}
/*
* Pass it on to SUPR3HardenedLdrLoad.
*/
return rc;
}
SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
{
/*
* Validate input.
*/
*phLdrMod = NIL_RTLDRMOD;
#ifdef VBOX_WITH_HARDENING
/*
* Verify the image file.
*/
if (RT_FAILURE(rc))
{
if (!RTErrInfoIsSet(pErrInfo))
return rc;
}
#endif
/*
* Try load it.
*/
}