VirtualBox

Changeset 78088 in vbox


Ignore:
Timestamp:
Apr 10, 2019 1:36:19 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
129944
Message:

Main/glue: Consolidated the bool parameters of com::Initialize() into a bit mask; added COM hack to prevent out-of-process IRundown::DoCallback calls. bugref:9425

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/com/com.h

    r76585 r78088  
    3939{
    4040
     41/** @name VBOX_COM_INIT_F_XXX - flags for com::Initialize().
     42 * @{ */
     43/** Windows: Caller is the GUI and needs a STA rather than MTA apartment. */
     44#define VBOX_COM_INIT_F_GUI             RT_BIT_32(0)
     45/** Windows: Auto registration updating, if privileged enough. */
     46#define VBOX_COM_INIT_F_AUTO_REG_UPDATE RT_BIT_32(1)
     47/** Windows: Opt-out of COM patching (client code should do this). */
     48#define VBOX_COM_INIT_F_NO_COM_PATCHING RT_BIT_32(2)
     49/** The default flags. */
     50#define VBOX_COM_INIT_F_DEFAULT         (VBOX_COM_INIT_F_AUTO_REG_UPDATE)
     51/** @} */
     52
    4153/**
    4254 *  Initializes the COM runtime.
     
    4658 *  @param fGui             if call is performed on the GUI thread
    4759 *  @param fAutoRegUpdate   if to do auto MS COM registration updates.
     60 *  @param fNoComPatching   Set this to skip the COM patching.
    4861 *  @return COM result code
    4962 */
    50 HRESULT Initialize(bool fGui = false, bool fAutoRegUpdate = true);
     63HRESULT Initialize(uint32_t fInitFlags = VBOX_COM_INIT_F_DEFAULT);
    5164
    5265/**
     
    114127                     PRTERRINFO pErrInfo);
    115128
     129#ifdef RT_OS_WINDOWS
     130void PatchComBugs(void);
     131#endif
     132
    116133} /* namespace com */
    117134
  • trunk/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp

    r76553 r78088  
    737737            throw RTCError("Out of memory\n");
    738738
    739         handleComError(com::Initialize(), "Failed to initialize COM");
     739        handleComError(com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING), "Failed to initialize COM");
    740740
    741741        MachineInfoList list;
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/COMDefs.cpp

    r76606 r78088  
    9090    LogFlowFuncEnter();
    9191
    92     HRESULT rc = com::Initialize(fGui);
     92    HRESULT rc = com::Initialize(fGui ? VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_GUI : VBOX_COM_INIT_F_DEFAULT);
    9393
    9494#if defined (VBOX_WITH_XPCOM)
  • trunk/src/VBox/Main/cbinding/VBoxCAPI.cpp

    r76553 r78088  
    394394        sessionIID = IID_ISession;
    395395
    396     HRESULT rc = com::Initialize();
     396    HRESULT rc = com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING);
    397397    if (FAILED(rc))
    398398    {
     
    669669        virtualBoxClientIID = IID_IVirtualBoxClient;
    670670
    671     HRESULT rc = com::Initialize();
     671    HRESULT rc = com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING);
    672672    if (FAILED(rc))
    673673    {
     
    728728VBoxClientThreadInitialize(void)
    729729{
    730     return com::Initialize();
     730    return com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING);
    731731}
    732732
  • trunk/src/VBox/Main/glue/initterm.cpp

    r76592 r78088  
    1919#if !defined(VBOX_WITH_XPCOM)
    2020
     21# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600
     22#  undef  _WIN32_WINNT
     23#  define _WIN32_WINNT 0x600 /* GetModuleHandleExW */
     24# endif
    2125# include <iprt/nt/nt-and-windows.h>
    2226# include <iprt/win/objbase.h>
     27# include <iprt/win/rpcproxy.h>
     28# include <rpcasync.h>
    2329
    2430#else /* !defined(VBOX_WITH_XPCOM) */
     
    5157#include <iprt/path.h>
    5258#include <iprt/string.h>
     59#include <iprt/system.h>
    5360#include <iprt/thread.h>
    5461
     
    192199
    193200/**
     201 * Replacement function for the InvokeStub method for the IRundown stub.
     202 */
     203static HRESULT STDMETHODCALLTYPE Rundown_InvokeStub(IRpcStubBuffer *pThis, RPCOLEMESSAGE *pMsg, IRpcChannelBuffer *pBuf)
     204{
     205    /*
     206     * Our mission here is to prevent remote calls to methods #8 and #9,
     207     * as these contain raw pointers to callback functions.
     208     *
     209     * Note! APIs like I_RpcServerInqTransportType, I_RpcBindingInqLocalClientPID
     210     *       and RpcServerInqCallAttributesW are not usable in this context without
     211     *       a rpc binding handle (latter two).
     212     *
     213     * P.S.  In more recent windows versions, the buffer implements a interface
     214     *       IID_IRpcChannelBufferMarshalingContext (undocumented) which has a
     215     *       GetIMarshallingContextAttribute() method that will return the client PID
     216     *       when asking for attribute #0x8000000e.
     217     */
     218    uint32_t const iMethod = pMsg->iMethod & 0xffff; /* Uncertain, but there are hints that the upper bits are flags. */
     219    HRESULT        hrc;
     220    if (   (   iMethod != 8
     221            && iMethod != 9)
     222        || (pMsg->rpcFlags & RPCFLG_LOCAL_CALL) )
     223        hrc = CStdStubBuffer_Invoke(pThis, pMsg, pBuf);
     224    else
     225    {
     226        LogRel(("Rundown_InvokeStub: Rejected call to CRundown::%s: rpcFlags=%#x cbBuffer=%#x dataRepresentation=%d buffer=%p:{%.*Rhxs} reserved1=%p reserved2={%p,%p,%p,%p,%p}\n",
     227                pMsg->iMethod == 8 ? "DoCallback" : "DoNonreentrantCallback", pMsg->rpcFlags, pMsg->cbBuffer,
     228                pMsg->dataRepresentation, pMsg->Buffer, RT_VALID_PTR(pMsg->Buffer) ? pMsg->cbBuffer : 0, pMsg->Buffer,
     229                pMsg->reserved1, pMsg->reserved2[0], pMsg->reserved2[1], pMsg->reserved2[2], pMsg->reserved2[3], pMsg->reserved2[4]));
     230        hrc = E_ACCESSDENIED;
     231    }
     232    return hrc;
     233}
     234
     235/**
     236 * Replaces the IRundown InvokeStub method with Rundown_InvokeStub so we can
     237 * reject remote calls to a couple of misdesigned methods.
     238 */
     239void PatchComBugs(void)
     240{
     241    static volatile bool s_fPatched = false;
     242    if (s_fPatched)
     243        return;
     244
     245    /*
     246     * The combase.dll / ole32.dll is exporting a DllGetClassObject function
     247     * that is implemented using NdrDllGetClassObject just like our own
     248     * proxy/stub DLL.  This means we can get at the stub interface lists,
     249     * since what NdrDllGetClassObject has CStdPSFactoryBuffer as layout.
     250     *
     251     * Note! Tried using CoRegisterPSClsid instead of this mess, but no luck.
     252     */
     253    /* Locate the COM DLL, it must be loaded by now: */
     254    HMODULE hmod = GetModuleHandleW(L"COMBASE.DLL");
     255    if (!hmod)
     256        hmod = GetModuleHandleW(L"OLE32.DLL"); /* w7 */
     257    AssertReturnVoid(hmod != NULL);
     258
     259    /* Resolve the class getter: */
     260    LPFNGETCLASSOBJECT pfnGetClassObject = (LPFNGETCLASSOBJECT)GetProcAddress(hmod, "DllGetClassObject");
     261    AssertReturnVoid(pfnGetClassObject != NULL);
     262
     263    /* Get the factory instance: */
     264    static const CLSID   s_PSOlePrx32ClsId = {0x00000320,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
     265    CStdPSFactoryBuffer *pFactoryBuffer = NULL;
     266    HRESULT hrc = pfnGetClassObject(s_PSOlePrx32ClsId, IID_IPSFactoryBuffer, (void **)&pFactoryBuffer);
     267    AssertMsgReturnVoid(SUCCEEDED(hrc),  ("hrc=%Rhrc\n",  hrc));
     268    AssertReturnVoid(pFactoryBuffer != NULL);
     269
     270    /*
     271     * Search thru the file list for the interface we want to patch.
     272     */
     273    static const IID s_IID_Rundown = {0x00000134,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
     274    decltype(CStdStubBuffer_Invoke) *pfnInvoke = (decltype(pfnInvoke))GetProcAddress(hmod, "CStdStubBuffer_Invoke");
     275    if (!pfnInvoke)
     276        pfnInvoke = (decltype(pfnInvoke))GetProcAddress(GetModuleHandleW(L"RPCRT4.DLL"), "CStdStubBuffer_Invoke");
     277
     278    unsigned cPatched = 0;
     279    unsigned cAlreadyPatched = 0;
     280    Assert(pFactoryBuffer->pProxyFileList != NULL);
     281    for (ProxyFileInfo const **ppCur = pFactoryBuffer->pProxyFileList; *ppCur != NULL; ppCur++)
     282    {
     283        ProxyFileInfo const *pCur = *ppCur;
     284
     285        if (pCur->pStubVtblList)
     286        {
     287            for (PCInterfaceStubVtblList const *ppCurStub = pCur->pStubVtblList; *ppCurStub != NULL; ppCurStub++)
     288            {
     289                PCInterfaceStubVtblList const pCurStub = *ppCurStub;
     290                IID const *piid = pCurStub->header.piid;
     291                if (piid)
     292                {
     293                    if (IsEqualIID(*piid, s_IID_Rundown))
     294                    {
     295                        if (pCurStub->Vtbl.Invoke == pfnInvoke)
     296                        {
     297                            DWORD fOld = 0;
     298                            if (VirtualProtect(&pCurStub->Vtbl.Invoke, sizeof(pCurStub->Vtbl.Invoke), PAGE_READWRITE, &fOld))
     299                            {
     300                                pCurStub->Vtbl.Invoke = Rundown_InvokeStub;
     301                                VirtualProtect(&pCurStub->Vtbl.Invoke, sizeof(pCurStub->Vtbl.Invoke), fOld, &fOld);
     302                                cPatched++;
     303                            }
     304                            else
     305                                AssertMsgFailed(("%d\n", GetLastError()));
     306                        }
     307                        else
     308                            cAlreadyPatched++;
     309                    }
     310                }
     311            }
     312       }
     313    }
     314
     315    /* done */
     316    pFactoryBuffer->lpVtbl->Release((IPSFactoryBuffer *)pFactoryBuffer);
     317
     318    /*
     319     * If we patched anything we should try prevent being unloaded.
     320     */
     321    if (cPatched > 0)
     322    {
     323        s_fPatched = true;
     324        HMODULE hmodSelf;
     325        AssertLogRelMsg(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
     326                                           (LPCWSTR)(uintptr_t)Rundown_InvokeStub, &hmodSelf),
     327                        ("last error: %u; Rundown_InvokeStub=%p\n", GetLastError(), Rundown_InvokeStub));
     328    }
     329    else
     330        AssertLogRelMsg(cAlreadyPatched > 0, ("COM patching of IRundown failed!\n"));
     331}
     332
     333
     334/**
    194335 *  The COM main thread handle. (The first caller of com::Initialize().)
    195336 */
     
    239380 * @return S_OK on success and a COM result code in case of failure.
    240381 */
    241 HRESULT Initialize(bool fGui /*= false*/, bool fAutoRegUpdate /*= true*/)
     382HRESULT Initialize(uint32_t fInitFlags /*=VBOX_COM_INIT_F_DEFAULT*/)
    242383{
    243384    HRESULT rc = E_FAIL;
    244     NOREF(fAutoRegUpdate);
    245385
    246386#if !defined(VBOX_WITH_XPCOM)
     
    252392     * API users already active, as that could lead to a bit of a mess.
    253393     */
    254     if (   fAutoRegUpdate
     394    if (   (fInitFlags & VBOX_COM_INIT_F_AUTO_REG_UPDATE)
    255395        && gCOMMainThread == NIL_RTTHREAD)
    256396    {
     
    303443     * !!!!! Please think twice before touching this code !!!!!
    304444     */
    305     DWORD flags = fGui ?
    306                   COINIT_APARTMENTTHREADED
    307                 | COINIT_SPEED_OVER_MEMORY
    308                 :
    309                   COINIT_MULTITHREADED
    310                 | COINIT_DISABLE_OLE1DDE
    311                 | COINIT_SPEED_OVER_MEMORY;
     445    DWORD flags = fInitFlags & VBOX_COM_INIT_F_GUI
     446                ?   COINIT_APARTMENTTHREADED
     447                  | COINIT_SPEED_OVER_MEMORY
     448                :   COINIT_MULTITHREADED
     449                  | COINIT_DISABLE_OLE1DDE
     450                  | COINIT_SPEED_OVER_MEMORY;
    312451
    313452    rc = CoInitializeEx(NULL, flags);
     
    316455     * "already initialized using the same apartment model") */
    317456    AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));
     457
     458    /*
     459     * IRundown has unsafe two methods we need to patch to prevent remote access.
     460     * Do that before we start using COM and open ourselves to possible attacks.
     461     */
     462    if (!(fInitFlags & VBOX_COM_INIT_F_NO_COM_PATCHING))
     463        PatchComBugs();
    318464
    319465    /* To be flow compatible with the XPCOM case, we return here if this isn't
     
    328474        fRc = false;
    329475
    330     if (fGui)
     476    if (fInitFlags & VBOX_COM_INIT_F_GUI)
    331477        Assert(RTThreadIsMain(hSelf));
    332478
     
    350496
    351497    /* Unused here */
    352     NOREF(fGui);
     498    RT_NOREF(fInitFlags);
    353499
    354500    if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true)
  • trunk/src/VBox/Main/src-server/win/svcmain.cpp

    r76592 r78088  
    945945                "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
    946946
    947     int nRet = 0;
    948     HRESULT hRes = com::Initialize(false /*fGui*/, fRun /*fAutoRegUpdate*/);
     947    AssertCompile(VBOX_COM_INIT_F_DEFAULT == VBOX_COM_INIT_F_AUTO_REG_UPDATE);
     948    HRESULT hRes = com::Initialize(fRun ? VBOX_COM_INIT_F_AUTO_REG_UPDATE : 0);
    949949    AssertLogRelMsg(SUCCEEDED(hRes), ("SVCMAIN: init failed: %Rhrc\n", hRes));
    950950
     
    955955    g_pModule->dwThreadID = GetCurrentThreadId();
    956956
     957    int nRet = 0;
    957958    if (!fRun)
    958959    {
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette