VirtualBox

Changeset 76091 in vbox for trunk/src/VBox/Main/src-server


Ignore:
Timestamp:
Dec 9, 2018 11:02:49 PM (6 years ago)
Author:
vboxsync
Message:

VBoxSVC: Hook all IVirtualBox calls to catch new client processes so we can watch them for termination. Work in progress. bugref:3300

Location:
trunk/src/VBox/Main/src-server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp

    r75663 r76091  
    2929#include <iprt/string.h>
    3030#include <iprt/stream.h>
     31#include <iprt/system.h>
    3132#include <iprt/thread.h>
    3233#include <iprt/uuid.h>
     
    172173////////////////////////////////////////////////////////////////////////////////
    173174
     175#if defined(RT_OS_WINDOWS) && defined(VBOXSVC_WITH_CLIENT_WATCHER)
     176/**
     177 * Client process watcher data.
     178 */
     179class WatchedClientProcess
     180{
     181public:
     182    WatchedClientProcess(RTPROCESS a_pid, HANDLE a_hProcess) RT_NOEXCEPT
     183        : m_pid(a_pid)
     184        , m_cRefs(1)
     185        , m_hProcess(a_hProcess)
     186    {
     187    }
     188
     189    ~WatchedClientProcess()
     190    {
     191        if (m_hProcess != NULL)
     192        {
     193            ::CloseHandle(m_hProcess);
     194            m_hProcess = NULL;
     195        }
     196        m_pid = NIL_RTPROCESS;
     197    }
     198
     199    /** The client PID.   */
     200    RTPROCESS           m_pid;
     201    /** Number of references to this structure. */
     202    uint32_t volatile   m_cRefs;
     203    /** Handle of the client process.
     204     * Ideally, we've got full query privileges, but we'll settle for waiting.  */
     205    HANDLE              m_hProcess;
     206};
     207typedef std::map<RTPROCESS, WatchedClientProcess *> WatchedClientProcessMap;
     208#endif
     209
     210
    174211typedef ObjectsList<Medium> MediaOList;
    175212typedef ObjectsList<GuestOSType> GuestOSTypesOList;
     
    181218typedef std::map<Guid, ComObjPtr<Medium> > HardDiskMap;
    182219
     220
    183221/**
    184222 *  Main VirtualBox data structure.
     
    189227{
    190228    Data()
    191         : pMainConfigFile(NULL),
    192           uuidMediaRegistry("48024e5c-fdd9-470f-93af-ec29f7ea518c"),
    193           uRegistryNeedsSaving(0),
    194           lockMachines(LOCKCLASS_LISTOFMACHINES),
    195           allMachines(lockMachines),
    196           lockGuestOSTypes(LOCKCLASS_LISTOFOTHEROBJECTS),
    197           allGuestOSTypes(lockGuestOSTypes),
    198           lockMedia(LOCKCLASS_LISTOFMEDIA),
    199           allHardDisks(lockMedia),
    200           allDVDImages(lockMedia),
    201           allFloppyImages(lockMedia),
    202           lockSharedFolders(LOCKCLASS_LISTOFOTHEROBJECTS),
    203           allSharedFolders(lockSharedFolders),
    204           lockDHCPServers(LOCKCLASS_LISTOFOTHEROBJECTS),
    205           allDHCPServers(lockDHCPServers),
    206           lockNATNetworks(LOCKCLASS_LISTOFOTHEROBJECTS),
    207           allNATNetworks(lockNATNetworks),
    208           mtxProgressOperations(LOCKCLASS_PROGRESSLIST),
    209           pClientWatcher(NULL),
    210           threadAsyncEvent(NIL_RTTHREAD),
    211           pAsyncEventQ(NULL),
    212           pAutostartDb(NULL),
    213           fSettingsCipherKeySet(false)
    214     {
     229        : pMainConfigFile(NULL)
     230        , uuidMediaRegistry("48024e5c-fdd9-470f-93af-ec29f7ea518c")
     231        , uRegistryNeedsSaving(0)
     232        , lockMachines(LOCKCLASS_LISTOFMACHINES)
     233        , allMachines(lockMachines)
     234        , lockGuestOSTypes(LOCKCLASS_LISTOFOTHEROBJECTS)
     235        , allGuestOSTypes(lockGuestOSTypes)
     236        , lockMedia(LOCKCLASS_LISTOFMEDIA)
     237        , allHardDisks(lockMedia)
     238        , allDVDImages(lockMedia)
     239        , allFloppyImages(lockMedia)
     240        , lockSharedFolders(LOCKCLASS_LISTOFOTHEROBJECTS)
     241        , allSharedFolders(lockSharedFolders)
     242        , lockDHCPServers(LOCKCLASS_LISTOFOTHEROBJECTS)
     243        , allDHCPServers(lockDHCPServers)
     244        , lockNATNetworks(LOCKCLASS_LISTOFOTHEROBJECTS)
     245        , allNATNetworks(lockNATNetworks)
     246        , mtxProgressOperations(LOCKCLASS_PROGRESSLIST)
     247        , pClientWatcher(NULL)
     248        , threadAsyncEvent(NIL_RTTHREAD)
     249        , pAsyncEventQ(NULL)
     250        , pAutostartDb(NULL)
     251        , fSettingsCipherKeySet(false)
     252#if defined(RT_OS_WINDOWS) && defined(VBOXSVC_WITH_CLIENT_WATCHER)
     253        , fWatcherIsReliable(RTSystemGetNtVersion() >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0))
     254#endif
     255    {
     256#if defined(RT_OS_WINDOWS) && defined(VBOXSVC_WITH_CLIENT_WATCHER)
     257        RTCritSectRwInit(&WatcherCritSect);
     258#endif
    215259    }
    216260
     
    310354    bool                                fSettingsCipherKeySet;
    311355    uint8_t                             SettingsCipherKey[RTSHA512_HASH_SIZE];
     356
     357#if defined(RT_OS_WINDOWS) && defined(VBOXSVC_WITH_CLIENT_WATCHER)
     358    /** Critical section protecting WatchedProcesses. */
     359    RTCRITSECTRW                        WatcherCritSect;
     360    /** Map of processes being watched, key is the PID. */
     361    WatchedClientProcessMap             WatchedProcesses;
     362    /** Set if the watcher is reliable, otherwise cleared.
     363     * The watcher goes unreliable when we run out of memory, fail open a client
     364     * process, or if the watcher thread gets messed up. */
     365    bool                                fWatcherIsReliable;
     366#endif
    312367};
    313368
     
    55525607#endif /* !RT_OS_WINDOWS */
    55535608
     5609#if defined(RT_OS_WINDOWS) && defined(VBOXSVC_WITH_CLIENT_WATCHER)
     5610
     5611# include <psapi.h> /* for GetProcessImageFileNameW */
     5612
     5613/**
     5614 * Callout from the wrapper.
     5615 */
     5616void VirtualBox::i_callHook(const char *a_pszFunction)
     5617{
     5618    RT_NOREF(a_pszFunction);
     5619
     5620    /*
     5621     * Let'see figure out who is calling.
     5622     * Note! Requires Vista+, so skip this entirely on older systems.
     5623     */
     5624    if (RTSystemGetNtVersion() >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0))
     5625    {
     5626        RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL };
     5627        RPC_STATUS rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs);
     5628        if (   rcRpc == RPC_S_OK
     5629            && CallAttribs.ClientPID != 0)
     5630        {
     5631            RTPROCESS const pidClient = (RTPROCESS)(uintptr_t)CallAttribs.ClientPID;
     5632            if (pidClient != RTProcSelf())
     5633            {
     5634                /** @todo LogRel2 later: */
     5635                LogRel(("i_callHook: %Rfn [ClientPID=%#zx/%zu IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid]\n",
     5636                        a_pszFunction, CallAttribs.ClientPID, CallAttribs.ClientPID, CallAttribs.IsClientLocal,
     5637                        CallAttribs.ProtocolSequence, CallAttribs.CallStatus, CallAttribs.CallType, CallAttribs.OpNum,
     5638                        &CallAttribs.InterfaceUuid));
     5639
     5640                /*
     5641                 * Do we know this client PID already?
     5642                 */
     5643                RTCritSectRwEnterShared(&m->WatcherCritSect);
     5644                WatchedClientProcessMap::iterator It = m->WatchedProcesses.find(pidClient);
     5645                if (It != m->WatchedProcesses.end())
     5646                    RTCritSectRwLeaveShared(&m->WatcherCritSect); /* Known process, nothing to do. */
     5647                else
     5648                {
     5649                    /* This is a new client process, start watching it. */
     5650                    RTCritSectRwLeaveShared(&m->WatcherCritSect);
     5651                    i_watchClientProcess(pidClient, a_pszFunction);
     5652                }
     5653            }
     5654        }
     5655        else
     5656            LogRel(("i_callHook: %Rfn - rcRpc=%#x ClientPID=%#zx/%zu !! [IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid]\n",
     5657                    a_pszFunction, rcRpc, CallAttribs.ClientPID, CallAttribs.ClientPID, CallAttribs.IsClientLocal,
     5658                    CallAttribs.ProtocolSequence, CallAttribs.CallStatus, CallAttribs.CallType, CallAttribs.OpNum,
     5659                    &CallAttribs.InterfaceUuid));
     5660    }
     5661}
     5662
     5663
     5664/**
     5665 * Wathces @a a_pidClient for termination.
     5666 *
     5667 * @returns true if successfully enabled watching of it, false if not.
     5668 * @param   a_pidClient     The PID to watch.
     5669 * @param   a_pszFunction   The function we which we detected the client in.
     5670 */
     5671bool VirtualBox::i_watchClientProcess(RTPROCESS a_pidClient, const char *a_pszFunction)
     5672{
     5673    RT_NOREF_PV(a_pszFunction);
     5674
     5675    /*
     5676     * Open the client process.
     5677     */
     5678    HANDLE hClient = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE /*fInherit*/, a_pidClient);
     5679    if (hClient == NULL)
     5680        hClient = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE , a_pidClient);
     5681    if (hClient == NULL)
     5682        hClient = OpenProcess(SYNCHRONIZE, FALSE , a_pidClient);
     5683    AssertLogRelMsgReturn(hClient != NULL, ("pidClient=%d (%#x) err=%d\n", a_pidClient, a_pidClient, GetLastError()),
     5684                          m->fWatcherIsReliable = false);
     5685
     5686    /*
     5687     * Create a new watcher structure and try add it to the map.
     5688     */
     5689    bool fRet = true;
     5690    WatchedClientProcess *pWatched = new (std::nothrow) WatchedClientProcess(a_pidClient, hClient);
     5691    if (pWatched)
     5692    {
     5693        RTCritSectRwEnterExcl(&m->WatcherCritSect);
     5694
     5695        WatchedClientProcessMap::iterator It = m->WatchedProcesses.find(a_pidClient);
     5696        if (It == m->WatchedProcesses.end())
     5697        {
     5698            try
     5699            {
     5700                m->WatchedProcesses.insert(WatchedClientProcessMap::value_type(a_pidClient, pWatched));
     5701            }
     5702            catch (std::bad_alloc &)
     5703            {
     5704                fRet = false;
     5705            }
     5706            if (fRet)
     5707            {
     5708                /*
     5709                 * Schedule it on a watcher thread.
     5710                 */
     5711                /** @todo later. */
     5712                RTCritSectRwLeaveExcl(&m->WatcherCritSect);
     5713            }
     5714            else
     5715            {
     5716                RTCritSectRwLeaveExcl(&m->WatcherCritSect);
     5717                delete pWatched;
     5718                LogRel(("VirtualBox::i_watchClientProcess: out of memory inserting into client map!\n"));
     5719            }
     5720        }
     5721        else
     5722        {
     5723            /*
     5724             * Someone raced us here, we lost.
     5725             */
     5726            RTCritSectRwLeaveExcl(&m->WatcherCritSect);
     5727            delete pWatched;
     5728        }
     5729    }
     5730    else
     5731    {
     5732        LogRel(("VirtualBox::i_watchClientProcess: out of memory!\n"));
     5733        CloseHandle(hClient);
     5734        m->fWatcherIsReliable = fRet = false;
     5735    }
     5736    return fRet;
     5737}
     5738
     5739
     5740/** Logs the RPC caller info to the release log. */
     5741/*static*/ void VirtualBox::i_logCaller(const char *a_pszFormat, ...)
     5742{
     5743    if (RTSystemGetNtVersion() >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0))
     5744    {
     5745        char szTmp[80];
     5746        va_list va;
     5747        va_start(va, a_pszFormat);
     5748        RTStrPrintfV(szTmp, sizeof(szTmp), a_pszFormat, va);
     5749        va_end(va);
     5750
     5751        RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL };
     5752        RPC_STATUS rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs);
     5753
     5754        RTUTF16 wszProcName[256];
     5755        wszProcName[0] = '\0';
     5756        if (rcRpc == 0 && CallAttribs.ClientPID != 0)
     5757        {
     5758            HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)(uintptr_t)CallAttribs.ClientPID);
     5759            if (hProcess)
     5760            {
     5761                RT_ZERO(wszProcName);
     5762                GetProcessImageFileNameW(hProcess, wszProcName, RT_ELEMENTS(wszProcName) - 1);
     5763                CloseHandle(hProcess);
     5764            }
     5765        }
     5766        LogRel(("%s [rcRpc=%#x ClientPID=%#zx/%zu (%ls) IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid]\n",
     5767                szTmp, rcRpc, CallAttribs.ClientPID, CallAttribs.ClientPID, wszProcName, CallAttribs.IsClientLocal,
     5768                CallAttribs.ProtocolSequence, CallAttribs.CallStatus, CallAttribs.CallType, CallAttribs.OpNum,
     5769                &CallAttribs.InterfaceUuid));
     5770    }
     5771}
     5772
     5773#endif /* RT_OS_WINDOWS && VBOXSVC_WITH_CLIENT_WATCHER */
     5774
     5775
    55545776/* vi: set tabstop=4 shiftwidth=4 expandtab: */
  • trunk/src/VBox/Main/src-server/win/svcmain.cpp

    r76071 r76091  
    553553}
    554554
    555 #ifdef DEBUG_bird
    556 # include <psapi.h> /* for GetProcessImageFileNameW */
    557 
    558 /** Logs the RPC caller info to the release log. */
    559 static void logCaller(const char *pszFormat, ...)
    560 {
    561     char szTmp[80];
    562     va_list va;
    563     va_start(va, pszFormat);
    564     RTStrPrintfV(szTmp, sizeof(szTmp), pszFormat, va);
    565     va_end(va);
    566 
    567     RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL };
    568     RPC_STATUS rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs);
    569 
    570     RTUTF16 wszProcName[256];
    571     wszProcName[0] = '\0';
    572     if (rcRpc == 0 && CallAttribs.ClientPID != 0)
    573     {
    574         HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)(uintptr_t)CallAttribs.ClientPID);
    575         if (hProcess)
    576         {
    577             RT_ZERO(wszProcName);
    578             GetProcessImageFileNameW(hProcess, wszProcName, RT_ELEMENTS(wszProcName) - 1);
    579             CloseHandle(hProcess);
    580         }
    581     }
    582     LogRel(("%s [rcRpc=%#x ClientPID=%#zx/%zu (%ls) IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid]\n",
    583             szTmp, rcRpc, CallAttribs.ClientPID, CallAttribs.ClientPID, wszProcName, CallAttribs.IsClientLocal,
    584             CallAttribs.ProtocolSequence, CallAttribs.CallStatus, CallAttribs.CallType, CallAttribs.OpNum,
    585             &CallAttribs.InterfaceUuid));
    586 }
    587555
    588556/**
    589  * Caller watcher wrapper exploration wrapping CComObjectCached.
    590  * @sa @bugref{3300}
     557 * Custom instantiation of CComObjectCached.
     558 *
     559 * This catches certain QueryInterface callers for the purpose of watching for
     560 * abnormal client process termination (@bugref{3300}).
     561 *
     562 * @todo just merge this into class VirtualBox VirtualBoxImpl.h
    591563 */
    592 template <class Base> class DebugWatcher : public Base
     564class VirtualBoxObjectCached : public VirtualBox
    593565{
    594566public:
    595     DebugWatcher(void *a_pWhatever = NULL) : Base(a_pWhatever)
    596     {
    597     }
    598 
    599     virtual ~DebugWatcher()
    600     {
    601     }
     567    VirtualBoxObjectCached(void * = NULL)
     568        : VirtualBox()
     569    {
     570    }
     571
     572    virtual ~VirtualBoxObjectCached()
     573    {
     574        m_iRef = LONG_MIN / 2; /* Catch refcount screwups by setting refcount something insane. */
     575        FinalRelease();
     576    }
     577
     578    /** @name IUnknown implementation for VirtualBox
     579     * @{  */
    602580
    603581    STDMETHOD_(ULONG, AddRef)() throw()
    604582    {
    605         ULONG cRefs = Base::AddRef();
    606         logCaller("AddRef -> %u", cRefs);
     583        ULONG cRefs = InternalAddRef();
     584        if (cRefs == 2)
     585        {
     586            AssertMsg(ATL::_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
     587            ATL::_pAtlModule->Lock();
     588        }
    607589        return cRefs;
    608590    }
     
    610592    STDMETHOD_(ULONG, Release)() throw()
    611593    {
    612         ULONG cRefs = Base::Release();
    613         logCaller("Release -> %u", cRefs);
     594        ULONG cRefs = InternalRelease();
     595        if (cRefs == 0)
     596            delete this;
     597        else if (cRefs == 1)
     598        {
     599            AssertMsg(ATL::_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
     600            ATL::_pAtlModule->Unlock();
     601        }
    614602        return cRefs;
    615603    }
     
    617605    STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
    618606    {
    619         HRESULT hrc = Base::QueryInterface(iid, ppvObj);
    620         logCaller("QueryInterface %RTuuid -> %Rhrc %p", iid, hrc, *ppvObj);
     607        HRESULT hrc = _InternalQueryInterface(iid, ppvObj);
     608#ifdef VBOXSVC_WITH_CLIENT_WATCHER
     609        i_logCaller("QueryInterface %RTuuid -> %Rhrc %p", &iid, hrc, *ppvObj);
     610#endif
    621611        return hrc;
    622612    }
    623613
    624     static HRESULT WINAPI CreateInstance(DebugWatcher<Base> **pp) throw()
    625     {
    626         AssertReturn(pp, E_POINTER);
    627         *pp = NULL;
     614    /** @} */
     615
     616    static HRESULT WINAPI CreateInstance(VirtualBoxObjectCached **ppObj) throw()
     617    {
     618        AssertReturn(ppObj, E_POINTER);
     619        *ppObj = NULL;
    628620
    629621        HRESULT hrc = E_OUTOFMEMORY;
    630         DebugWatcher<Base> *p = new (std::nothrow) DebugWatcher<Base>();
     622        VirtualBoxObjectCached *p = new (std::nothrow) VirtualBoxObjectCached();
    631623        if (p)
    632624        {
     
    640632                delete p;
    641633            else
    642                 *pp = p;
     634                *ppObj = p;
    643635        }
    644636        return hrc;
    645637    }
    646 
    647638};
    648639
    649 #endif /* DEBUG_bird */
    650640
    651641/**
     
    664654STDMETHODIMP VirtualBoxClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
    665655{
    666 # ifdef DEBUG_bird
    667     logCaller("VirtualBoxClassFactory::CreateInstance: %RTuuid", riid);
     656# ifdef VBOXSVC_WITH_CLIENT_WATCHER
     657    VirtualBox::i_logCaller("VirtualBoxClassFactory::CreateInstance: %RTuuid", riid);
    668658# endif
    669659    HRESULT hrc = E_POINTER;
     
    703693                        {
    704694                            ATL::_pAtlModule->Lock();
    705 #ifdef DEBUG_bird
    706                             DebugWatcher<ATL::CComObjectCached<VirtualBox>> *p;
    707                             m_hrcCreate = hrc = DebugWatcher<ATL::CComObjectCached<VirtualBox>>::CreateInstance(&p);
    708 #else
    709                             ATL::CComObjectCached<VirtualBox> *p;
    710                             m_hrcCreate = hrc = ATL::CComObjectCached<VirtualBox>::CreateInstance(&p);
    711 #endif
     695                            VirtualBoxObjectCached *p;
     696                            m_hrcCreate = hrc = VirtualBoxObjectCached::CreateInstance(&p);
    712697                            if (SUCCEEDED(hrc))
    713698                            {
Note: See TracChangeset for help on using the changeset viewer.

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