SUPLib.cpp revision 344115a50dfcaf97123d38b056161195a7e4e48c
/* $Id$ */
/** @file
* VirtualBox Support Library - Common code.
*/
/*
* Copyright (C) 2006-2010 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 "SUPLibInternal.h"
#include "SUPDrvIOC.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** R0 VMM module name. */
#define VMMR0_NAME "VMMR0"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef FNCALLVMMR0 *PFNCALLVMMR0;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Init counter. */
/** Whether we've been preinitied. */
static bool g_fPreInited = false;
/** The SUPLib instance data.
* Well, at least parts of it, specifically the parts that are being handed over
* via the pre-init mechanism from the hardened executable stub. */
{
#if defined(RT_OS_DARWIN)
, NULL
#elif defined(RT_OS_LINUX)
, false
#endif
};
/** Pointer to the Global Information Page.
*
* This pointer is valid as long as SUPLib has a open session. Anyone using
* the page must treat this pointer as highly volatile and not trust it beyond
* one transaction.
*
* @todo This will probably deserve it's own session or some other good solution...
*/
/** Address of the ring-0 mapping of the GIP. */
/** The physical address of the GIP. */
/** The negotiated cookie. */
uint32_t g_u32Cookie = 0;
/** The negotiated session cookie. */
/** Session handle. */
/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
static PSUPQUERYFUNCS g_pFunctions;
/** VMMR0 Load Address. */
/** PAGE_ALLOC_EX sans kernel mapping support indicator. */
static bool g_fSupportsPageAllocNoKernel = true;
/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
static uint32_t g_u32FakeMode = ~0;
/*******************************************************************************
* 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);
/** Touch a range of pages. */
{
while (cPages-- > 0)
{
ASMAtomicCmpXchgU32(pu32, 0, 0);
}
}
SUPR3DECL(int) SUPR3Install(void)
{
return suplibOsInstall();
}
SUPR3DECL(int) SUPR3Uninstall(void)
{
return suplibOsUninstall();
}
{
/*
* The caller is kind of trustworthy, just perform some basic checks.
*
* Note! Do not do any fancy stuff here because IPRT has NOT been
* initialized at this point.
*/
if (!VALID_PTR(pPreInitData))
return VERR_INVALID_POINTER;
if (g_fPreInited || g_cInits > 0)
return VERR_WRONG_ORDER;
return VERR_INVALID_MAGIC;
if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
return VERR_INVALID_HANDLE;
if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
return VERR_INVALID_PARAMETER;
/*
* Hand out the data.
*/
if (RT_FAILURE(rc))
return rc;
/** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
{
g_fPreInited = true;
}
return VINF_SUCCESS;
}
{
/*
* Perform some sanity checks.
* (Got some trouble with compile time member alignment assertions.)
*/
/*
* Check if already initialized.
*/
if (ppSession)
*ppSession = g_pSession;
if (g_cInits++ > 0)
return VINF_SUCCESS;
/*
* Check for fake mode.
*
* Fake mode is used when we're doing smoke testing and debugging.
* It's also useful on platforms where we haven't root access or which
* we haven't ported the support driver to.
*/
if (g_u32FakeMode == ~0U)
{
else
ASMAtomicCmpXchgU32(&g_u32FakeMode, 0, ~0U);
}
if (RT_UNLIKELY(g_u32FakeMode))
return supInitFake(ppSession);
/*
* Open the support driver.
*/
if (RT_SUCCESS(rc))
{
/*
* Negotiate the cookie.
*/
? 0x00160001
if ( RT_SUCCESS(rc)
{
{
/*
* Query the functions.
*/
PSUPQUERYFUNCS pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
if (pFuncsReq)
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq, SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
/*
* Map the GIP into userspace.
*/
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
/*
* Set the globals and return success.
*/
ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
if (ppSession)
return VINF_SUCCESS;
}
}
/* bailout */
}
else
rc = VERR_NO_MEMORY;
}
else
{
LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, uMinVersion));
}
}
else
{
if (RT_SUCCESS(rc))
{
LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
}
else
{
/* for pre 0x00060000 drivers */
LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
}
}
}
g_cInits--;
return rc;
}
/**
* Fake mode init.
*/
{
Log(("SUP: Fake mode!\n"));
static const SUPFUNC s_aFakeFunctions[] =
{
/* name function */
{ "SUPR0AbsIs64bit", 0 },
{ "SUPR0Abs64bitKernelCS", 0 },
{ "SUPR0Abs64bitKernelSS", 0 },
{ "SUPR0Abs64bitKernelDS", 0 },
{ "SUPR0AbsKernelCS", 8 },
{ "SUPR0AbsKernelSS", 16 },
{ "SUPR0AbsKernelDS", 16 },
{ "SUPR0AbsKernelES", 16 },
{ "SUPR0AbsKernelFS", 24 },
{ "SUPR0AbsKernelGS", 32 },
{ "SUPR0ComponentRegisterFactory", 0xefeefffd },
{ "SUPR0ComponentDeregisterFactory", 0xefeefffe },
{ "SUPR0ComponentQueryFactory", 0xefeeffff },
{ "SUPR0ObjRegister", 0xefef0000 },
{ "SUPR0ObjAddRef", 0xefef0001 },
{ "SUPR0ObjAddRefEx", 0xefef0001 },
{ "SUPR0ObjRelease", 0xefef0002 },
{ "SUPR0ObjVerifyAccess", 0xefef0003 },
{ "SUPR0LockMem", 0xefef0004 },
{ "SUPR0UnlockMem", 0xefef0005 },
{ "SUPR0ContAlloc", 0xefef0006 },
{ "SUPR0ContFree", 0xefef0007 },
{ "SUPR0MemAlloc", 0xefef0008 },
{ "SUPR0MemGetPhys", 0xefef0009 },
{ "SUPR0MemFree", 0xefef000a },
{ "SUPR0Printf", 0xefef000b },
{ "SUPR0GetPagingMode", 0xefef000c },
{ "SUPR0EnableVTx", 0xefef000e },
{ "RTMemAlloc", 0xefef000f },
{ "RTMemAllocZ", 0xefef0010 },
{ "RTMemFree", 0xefef0011 },
{ "RTR0MemObjAddress", 0xefef0012 },
{ "RTR0MemObjAddressR3", 0xefef0013 },
{ "RTR0MemObjAllocPage", 0xefef0014 },
{ "RTR0MemObjAllocPhysNC", 0xefef0015 },
{ "RTR0MemObjAllocLow", 0xefef0016 },
{ "RTR0MemObjEnterPhys", 0xefef0017 },
{ "RTR0MemObjFree", 0xefef0018 },
{ "RTR0MemObjGetPagePhysAddr", 0xefef0019 },
{ "RTR0MemObjMapUser", 0xefef001a },
{ "RTR0MemObjMapKernel", 0xefef001b },
{ "RTR0MemObjMapKernelEx", 0xefef001c },
{ "RTMpGetArraySize", 0xefef001c },
{ "RTProcSelf", 0xefef001d },
{ "RTR0ProcHandleSelf", 0xefef001e },
{ "RTSemEventCreate", 0xefef001f },
{ "RTSemEventSignal", 0xefef0020 },
{ "RTSemEventWait", 0xefef0021 },
{ "RTSemEventWaitNoResume", 0xefef0022 },
{ "RTSemEventDestroy", 0xefef0023 },
{ "RTSemEventMultiCreate", 0xefef0024 },
{ "RTSemEventMultiSignal", 0xefef0025 },
{ "RTSemEventMultiReset", 0xefef0026 },
{ "RTSemEventMultiWait", 0xefef0027 },
{ "RTSemEventMultiWaitNoResume", 0xefef0028 },
{ "RTSemEventMultiDestroy", 0xefef0029 },
{ "RTSemFastMutexCreate", 0xefef002a },
{ "RTSemFastMutexDestroy", 0xefef002b },
{ "RTSemFastMutexRequest", 0xefef002c },
{ "RTSemFastMutexRelease", 0xefef002d },
{ "RTSpinlockCreate", 0xefef002e },
{ "RTSpinlockDestroy", 0xefef002f },
{ "RTSpinlockAcquire", 0xefef0030 },
{ "RTSpinlockRelease", 0xefef0031 },
{ "RTSpinlockAcquireNoInts", 0xefef0032 },
{ "RTSpinlockReleaseNoInts", 0xefef0033 },
{ "RTTimeNanoTS", 0xefef0034 },
{ "RTTimeMillieTS", 0xefef0035 },
{ "RTTimeSystemNanoTS", 0xefef0036 },
{ "RTTimeSystemMillieTS", 0xefef0037 },
{ "RTThreadNativeSelf", 0xefef0038 },
{ "RTThreadSleep", 0xefef0039 },
{ "RTThreadYield", 0xefef003a },
{ "RTTimerCreate", 0xefef003a },
{ "RTTimerCreateEx", 0xefef003a },
{ "RTTimerDestroy", 0xefef003a },
{ "RTTimerStart", 0xefef003a },
{ "RTTimerStop", 0xefef003a },
{ "RTTimerChangeInterval", 0xefef003a },
{ "RTTimerGetSystemGranularity", 0xefef003a },
{ "RTTimerRequestSystemGranularity", 0xefef003a },
{ "RTTimerReleaseSystemGranularity", 0xefef003a },
{ "RTTimerCanDoHighResolution", 0xefef003a },
{ "RTLogDefaultInstance", 0xefef003b },
{ "RTLogRelDefaultInstance", 0xefef003c },
{ "RTLogSetDefaultInstanceThread", 0xefef003d },
{ "RTLogLogger", 0xefef003e },
{ "RTLogLoggerEx", 0xefef003f },
{ "RTLogLoggerExV", 0xefef0040 },
{ "RTAssertMsg1", 0xefef0041 },
{ "RTAssertMsg2", 0xefef0042 },
{ "RTAssertMsg2V", 0xefef0043 },
{ "SUPR0QueryVTCaps", 0xefef0044 },
};
/* fake r0 functions. */
g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
if (g_pFunctions)
{
if (ppSession)
*ppSession = g_pSession;
/* fake the GIP. */
if (g_pSUPGlobalInfoPage)
{
/* the page is supposed to be invalid, so don't set the magic. */
return VINF_SUCCESS;
}
g_pFunctions = NULL;
}
return VERR_NO_MEMORY;
}
{
/*
* Verify state.
*/
if (g_cInits == 0)
return VERR_WRONG_ORDER;
{
/*
* NULL the GIP pointer.
*/
if (g_pSUPGlobalInfoPage)
{
ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPage);
ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPageR0);
/* just a little safe guard against threads using the page. */
RTThreadSleep(50);
}
/*
* Close the support driver.
*/
if (rc)
return rc;
g_u32Cookie = 0;
g_u32SessionCookie = 0;
g_cInits = 0;
}
else
g_cInits--;
return 0;
}
{
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
#ifdef RT_ARCH_AMD64
return SUPPAGINGMODE_AMD64_GLOBAL_NX;
#else
return SUPPAGINGMODE_32_BIT_GLOBAL;
#endif
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
if ( RT_FAILURE(rc)
{
}
}
/**
* For later.
*/
static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
{
return VERR_NOT_SUPPORTED;
}
{
return VERR_INTERNAL_ERROR;
}
SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
{
/*
* The following operations don't belong here.
*/
&& uOperation != SUP_VMMR0_DO_NOP,
("%#x\n", uOperation),
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
int rc;
if (!pReqHdr)
{
/* no data. */
if (RT_SUCCESS(rc))
}
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
if (RT_SUCCESS(rc))
}
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0_BIG, pReq, SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
if (RT_SUCCESS(rc))
}
else
return rc;
}
{
/*
* The following operations don't belong here.
*/
&& uOperation != SUP_VMMR0_DO_NOP,
("%#x\n", uOperation),
}
{
if (RT_UNLIKELY(g_u32FakeMode))
return VINF_SUCCESS;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
if (RT_SUCCESS(rc))
return rc;
}
SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
{
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
return VERR_NOT_SUPPORTED;
int rc;
if (!pReqHdr)
{
/* no data. */
if (RT_SUCCESS(rc))
}
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
if (RT_SUCCESS(rc))
}
else /** @todo may have to remove the size limits one this request... */
return rc;
}
/**
* Worker for the SUPR3Logger* APIs.
*
* @returns VBox status code.
* @param enmWhich Which logger.
* @param fWhat What to do with the logger.
* @param pszFlags The flags settings.
* @param pszGroups The groups settings.
* @param pszDest The destination specificier.
*/
static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
{
switch (enmWhich)
{
default:
return VERR_INVALID_PARAMETER;
}
if (cchFlags)
{
}
else
if (cchGroups)
{
}
else
if (cchDest)
{
}
else
if (!off)
{
off++;
}
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
if (RT_SUCCESS(rc))
return rc;
}
SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
{
return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_SETTINGS, pszFlags, pszGroups, pszDest);
}
SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
{
}
{
}
{
/*
* Validate.
*/
/*
* Call OS specific worker.
*/
}
{
/*
* Validate.
*/
/*
* Call OS specific worker.
*/
}
/**
* Locks down the physical memory backing a virtual memory
* range in the current process.
*
* @returns VBox status code.
* @param pvStart Start of virtual memory range.
* Must be page aligned.
* @param cPages Number of pages.
* @param paPages Where to store the physical page addresses returned.
* On entry this will point to an array of with cbMemory >> PAGE_SHIFT entries.
*/
{
/*
* Validate.
*/
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
while (iPage-- > 0)
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
{
}
}
}
else
return rc;
}
/**
* Releases locked down pages.
*
* @returns VBox status code.
* @param pvStart Start of virtual memory range previously locked
* down by SUPPageLock().
*/
{
/*
* Validate.
*/
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
return VINF_SUCCESS;
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
return rc;
}
/**
* Fallback for SUPR3PageAllocEx on systems where RTR0MemObjPhysAllocNC isn't
* supported.
*/
{
if (RT_SUCCESS(rc))
{
if (!paPages)
if (RT_FAILURE(rc))
}
return rc;
}
SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
{
/*
* Validate.
*/
if (pR0Ptr)
*pR0Ptr = NIL_RTR0PTR;
AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
if (!pv)
return VERR_NO_MEMORY;
if (pR0Ptr)
if (paPages)
{
}
return VINF_SUCCESS;
}
/*
* Use fallback for non-R0 mapping?
*/
if ( !pR0Ptr
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
if (pReq)
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (pR0Ptr)
if (paPages)
{
}
#ifdef RT_OS_DARWIN /* HACK ALERT! */
#endif
}
else if ( rc == VERR_NOT_SUPPORTED
&& !pR0Ptr)
{
g_fSupportsPageAllocNoKernel = false;
}
}
}
else
return rc;
}
SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
{
/*
* Validate.
*/
*pR0Ptr = NIL_RTR0PTR;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
return VERR_NOT_SUPPORTED;
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
return rc;
}
SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
{
/*
* Validate.
*/
AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
/*
* Some OSes can do this from ring-3, so try that before we
* issue the IOCtl to the SUPDRV kernel module.
* (Yea, this isn't very nice, but just try get the job done for now.)
*/
#if !defined(RT_OS_SOLARIS)
#endif
if (RT_SUCCESS(rc))
return rc;
}
{
/*
* Validate.
*/
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Try normal free first, then if it fails check if we're using the fallback
* for the allocations without kernel mappings and attempt unlocking it.
*/
if (RT_SUCCESS(rc))
{
if ( rc == VERR_INVALID_PARAMETER
{
if (RT_SUCCESS(rc2))
}
}
return rc;
}
{
/*
* Validate.
*/
*pHCPhys = NIL_RTHCPHYS;
if (pR0Ptr)
*pR0Ptr = NIL_RTR0PTR;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
if (pR0Ptr)
if (pHCPhys)
return pv;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if ( RT_SUCCESS(rc)
{
if (pR0Ptr)
#ifdef RT_OS_DARWIN /* HACK ALERT! */
#endif
}
return NULL;
}
{
/*
* Validate.
*/
if (!pv)
return VINF_SUCCESS;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
return rc;
}
{
/*
* Validate.
*/
AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
if (!*ppvPages)
return VERR_NO_LOW_MEMORY;
/* fake physical addresses. */
while (iPage-- > 0)
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
if (pReq)
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (ppvPagesR0)
if (paPages)
{
}
#ifdef RT_OS_DARWIN /* HACK ALERT! */
#endif
}
}
else
return rc;
}
{
/*
* Validate.
*/
if (!pv)
return VINF_SUCCESS;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
return rc;
}
{
/*
* Quick input validation.
*/
AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
file is the same we verified after opening it. */
/*
* Only do the actual check in hardened builds.
*/
#ifdef VBOX_WITH_HARDENING
if (RT_FAILURE(rc))
LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
return rc;
#else
return VINF_SUCCESS;
#endif
}
{
/*
* Quick input validation.
*/
/*
* Get the executable image path as we need it for all the tests here.
*/
char szExecPath[RTPATH_MAX];
int rc;
if (fInternal)
{
/*
* Internal applications must be launched directly without any PATH
* searching involved.
*/
/*
* Internal applications must reside in or under the
* RTPathAppPrivateArch directory.
*/
char szAppPrivateArch[RTPATH_MAX];
if (RT_FAILURE(rc))
"RTPathAppPrivateArch failed with rc=%Rrc", rc);
"Internal executable does reside under RTPathAppPrivateArch");
"Internal executable does reside under RTPathAppPrivateArch");
}
#ifdef VBOX_WITH_HARDENING
/*
* Verify that the image file and parent directories are sane.
*/
if (RT_FAILURE(rc))
return rc;
#endif
return VINF_SUCCESS;
}
SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo)
{
/*
* Quick input validation
*/
/*
* Only do the actual check in hardened builds.
*/
#ifdef VBOX_WITH_HARDENING
return rc;
#else
return VINF_SUCCESS;
#endif
}
{
/*
* Quick input validation
*/
/*
* Only do the actual check in hardened builds.
*/
#ifdef VBOX_WITH_HARDENING
return rc;
#else
return VINF_SUCCESS;
#endif
}
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)
{
int rc = VINF_SUCCESS;
#ifdef VBOX_WITH_HARDENING
/*
* Check that the module can be trusted.
*/
#endif
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_u32FakeMode)
{
*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_u32FakeMode)
{
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_u32FakeMode)
{
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
if (RT_SUCCESS(rc))
}
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
{
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_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Free the requested module.
*/
if (RT_SUCCESS(rc))
if ( RT_SUCCESS(rc)
return rc;
}
{
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
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);
}
{
if (g_pSUPGlobalInfoPage)
{
return VINF_SUCCESS;
}
*pHCPhys = NIL_RTHCPHYS;
return VERR_WRONG_ORDER;
}
/**
* 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 (!RTPathHaveExt(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 (!RTPathHaveExt(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)
{
int rc;
/*
* 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.
*/
}
SUPR3DECL(int) SUPR3QueryVTxSupported(void)
{
#ifdef RT_OS_LINUX
return suplibOsQueryVTxSupported();
#else
return VINF_SUCCESS;
#endif
}
{
*pfCaps = 0;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
return VINF_SUCCESS;
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
return rc;
}