cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

provider.cpp (13181B)


      1/*
      2 * QEMU Guest Agent win32 VSS Provider implementations
      3 *
      4 * Copyright Hitachi Data Systems Corp. 2013
      5 *
      6 * Authors:
      7 *  Tomoki Sekiyama   <tomoki.sekiyama@hds.com>
      8 *
      9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10 * See the COPYING file in the top-level directory.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "vss-common.h"
     15#include <inc/win2003/vscoordint.h>
     16#include <inc/win2003/vsprov.h>
     17
     18#define VSS_TIMEOUT_MSEC (60*1000)
     19
     20static long g_nComObjsInUse;
     21HINSTANCE g_hinstDll;
     22
     23/* VSS common GUID's */
     24
     25const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
     26    {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
     27const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
     28    {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
     29
     30const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
     31    {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
     32const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
     33    {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
     34const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
     35    {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
     36const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
     37    {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
     38
     39const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
     40    {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
     41
     42
     43void LockModule(BOOL lock)
     44{
     45    if (lock) {
     46        InterlockedIncrement(&g_nComObjsInUse);
     47    } else {
     48        InterlockedDecrement(&g_nComObjsInUse);
     49    }
     50}
     51
     52/* Empty enumerator for VssObject */
     53
     54class CQGAVSSEnumObject : public IVssEnumObject
     55{
     56public:
     57    STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
     58    STDMETHODIMP_(ULONG) AddRef();
     59    STDMETHODIMP_(ULONG) Release();
     60
     61    /* IVssEnumObject Methods */
     62    STDMETHODIMP Next(
     63        ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched);
     64    STDMETHODIMP Skip(ULONG celt);
     65    STDMETHODIMP Reset(void);
     66    STDMETHODIMP Clone(IVssEnumObject **ppenum);
     67
     68    /* CQGAVSSEnumObject Methods */
     69    CQGAVSSEnumObject();
     70    ~CQGAVSSEnumObject();
     71
     72private:
     73    long m_nRefCount;
     74};
     75
     76CQGAVSSEnumObject::CQGAVSSEnumObject()
     77{
     78    m_nRefCount = 0;
     79    LockModule(TRUE);
     80}
     81
     82CQGAVSSEnumObject::~CQGAVSSEnumObject()
     83{
     84    LockModule(FALSE);
     85}
     86
     87STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
     88{
     89    if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
     90        *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
     91        AddRef();
     92        return S_OK;
     93    }
     94    *ppObj = NULL;
     95    return E_NOINTERFACE;
     96}
     97
     98STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
     99{
    100    return InterlockedIncrement(&m_nRefCount);
    101}
    102
    103STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
    104{
    105    long nRefCount = InterlockedDecrement(&m_nRefCount);
    106    if (m_nRefCount == 0) {
    107        delete this;
    108    }
    109    return nRefCount;
    110}
    111
    112STDMETHODIMP CQGAVSSEnumObject::Next(
    113    ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
    114{
    115    *pceltFetched = 0;
    116    return S_FALSE;
    117}
    118
    119STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
    120{
    121    return S_FALSE;
    122}
    123
    124STDMETHODIMP CQGAVSSEnumObject::Reset(void)
    125{
    126    return S_OK;
    127}
    128
    129STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
    130{
    131    return E_NOTIMPL;
    132}
    133
    134
    135/* QGAVssProvider */
    136
    137class CQGAVssProvider :
    138    public IVssSoftwareSnapshotProvider,
    139    public IVssProviderCreateSnapshotSet,
    140    public IVssProviderNotifications
    141{
    142public:
    143    STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
    144    STDMETHODIMP_(ULONG) AddRef();
    145    STDMETHODIMP_(ULONG) Release();
    146
    147    /* IVssSoftwareSnapshotProvider Methods */
    148    STDMETHODIMP SetContext(LONG lContext);
    149    STDMETHODIMP GetSnapshotProperties(
    150        VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp);
    151    STDMETHODIMP Query(
    152        VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
    153        VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum);
    154    STDMETHODIMP DeleteSnapshots(
    155        VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
    156        BOOL bForceDelete, LONG *plDeletedSnapshots,
    157        VSS_ID *pNondeletedSnapshotID);
    158    STDMETHODIMP BeginPrepareSnapshot(
    159        VSS_ID SnapshotSetId, VSS_ID SnapshotId,
    160        VSS_PWSZ pwszVolumeName, LONG lNewContext);
    161    STDMETHODIMP IsVolumeSupported(
    162        VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider);
    163    STDMETHODIMP IsVolumeSnapshotted(
    164        VSS_PWSZ pwszVolumeName, BOOL *pbSnapshotsPresent,
    165        LONG *plSnapshotCompatibility);
    166    STDMETHODIMP SetSnapshotProperty(
    167        VSS_ID SnapshotId, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId,
    168        VARIANT vProperty);
    169    STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId);
    170    STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync);
    171
    172    /* IVssProviderCreateSnapshotSet Methods */
    173    STDMETHODIMP EndPrepareSnapshots(VSS_ID SnapshotSetId);
    174    STDMETHODIMP PreCommitSnapshots(VSS_ID SnapshotSetId);
    175    STDMETHODIMP CommitSnapshots(VSS_ID SnapshotSetId);
    176    STDMETHODIMP PostCommitSnapshots(
    177        VSS_ID SnapshotSetId, LONG lSnapshotsCount);
    178    STDMETHODIMP PreFinalCommitSnapshots(VSS_ID SnapshotSetId);
    179    STDMETHODIMP PostFinalCommitSnapshots(VSS_ID SnapshotSetId);
    180    STDMETHODIMP AbortSnapshots(VSS_ID SnapshotSetId);
    181
    182    /* IVssProviderNotifications Methods */
    183    STDMETHODIMP OnLoad(IUnknown *pCallback);
    184    STDMETHODIMP OnUnload(BOOL bForceUnload);
    185
    186    /* CQGAVssProvider Methods */
    187    CQGAVssProvider();
    188    ~CQGAVssProvider();
    189
    190private:
    191    long m_nRefCount;
    192};
    193
    194CQGAVssProvider::CQGAVssProvider()
    195{
    196    m_nRefCount = 0;
    197    LockModule(TRUE);
    198}
    199
    200CQGAVssProvider::~CQGAVssProvider()
    201{
    202    LockModule(FALSE);
    203}
    204
    205STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
    206{
    207    if (riid == IID_IUnknown) {
    208        *ppObj = static_cast<void*>(this);
    209        AddRef();
    210        return S_OK;
    211    }
    212    if (riid == IID_IVssSoftwareSnapshotProvider) {
    213        *ppObj = static_cast<void*>(
    214            static_cast<IVssSoftwareSnapshotProvider*>(this));
    215        AddRef();
    216        return S_OK;
    217    }
    218    if (riid == IID_IVssProviderCreateSnapshotSet) {
    219        *ppObj = static_cast<void*>(
    220            static_cast<IVssProviderCreateSnapshotSet*>(this));
    221        AddRef();
    222        return S_OK;
    223    }
    224    if (riid == IID_IVssProviderNotifications) {
    225        *ppObj = static_cast<void*>(
    226            static_cast<IVssProviderNotifications*>(this));
    227        AddRef();
    228        return S_OK;
    229    }
    230    *ppObj = NULL;
    231    return E_NOINTERFACE;
    232}
    233
    234STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
    235{
    236    return InterlockedIncrement(&m_nRefCount);
    237}
    238
    239STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
    240{
    241    long nRefCount = InterlockedDecrement(&m_nRefCount);
    242    if (m_nRefCount == 0) {
    243        delete this;
    244    }
    245    return nRefCount;
    246}
    247
    248
    249/*
    250 * IVssSoftwareSnapshotProvider methods
    251 */
    252
    253STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
    254{
    255    return S_OK;
    256}
    257
    258STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
    259    VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
    260{
    261    return VSS_E_OBJECT_NOT_FOUND;
    262}
    263
    264STDMETHODIMP CQGAVssProvider::Query(
    265    VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
    266    VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
    267{
    268    try {
    269        *ppEnum = new CQGAVSSEnumObject;
    270    } catch (...) {
    271        return E_OUTOFMEMORY;
    272    }
    273    (*ppEnum)->AddRef();
    274    return S_OK;
    275}
    276
    277STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
    278    VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
    279    BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
    280{
    281    *plDeletedSnapshots = 0;
    282    *pNondeletedSnapshotID = SourceObjectId;
    283    return S_OK;
    284}
    285
    286STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
    287    VSS_ID SnapshotSetId, VSS_ID SnapshotId,
    288    VSS_PWSZ pwszVolumeName, LONG lNewContext)
    289{
    290    return S_OK;
    291}
    292
    293STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
    294    VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
    295{
    296    HANDLE hEventFrozen;
    297
    298    /* Check if a requester is qemu-ga by whether an event is created */
    299    hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
    300    if (!hEventFrozen) {
    301        *pbSupportedByThisProvider = FALSE;
    302        return S_OK;
    303    }
    304    CloseHandle(hEventFrozen);
    305
    306    *pbSupportedByThisProvider = TRUE;
    307    return S_OK;
    308}
    309
    310STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
    311    BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
    312{
    313    *pbSnapshotsPresent = FALSE;
    314    *plSnapshotCompatibility = 0;
    315    return S_OK;
    316}
    317
    318STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
    319    VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
    320{
    321    return E_NOTIMPL;
    322}
    323
    324STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
    325{
    326    return E_NOTIMPL;
    327}
    328
    329STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
    330    VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
    331{
    332    return E_NOTIMPL;
    333}
    334
    335
    336/*
    337 * IVssProviderCreateSnapshotSet methods
    338 */
    339
    340STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
    341{
    342    return S_OK;
    343}
    344
    345STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
    346{
    347    return S_OK;
    348}
    349
    350STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
    351{
    352    HRESULT hr = S_OK;
    353    HANDLE hEventFrozen, hEventThaw, hEventTimeout;
    354
    355    hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
    356    if (!hEventFrozen) {
    357        return E_FAIL;
    358    }
    359
    360    hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
    361    if (!hEventThaw) {
    362        CloseHandle(hEventFrozen);
    363        return E_FAIL;
    364    }
    365
    366    hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
    367    if (!hEventTimeout) {
    368        CloseHandle(hEventFrozen);
    369        CloseHandle(hEventThaw);
    370        return E_FAIL;
    371    }
    372
    373    /* Send event to qemu-ga to notify filesystem is frozen */
    374    SetEvent(hEventFrozen);
    375
    376    /* Wait until the snapshot is taken by the host. */
    377    if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
    378        /* Send event to qemu-ga to notify the provider is timed out */
    379        SetEvent(hEventTimeout);
    380    }
    381
    382    CloseHandle(hEventThaw);
    383    CloseHandle(hEventFrozen);
    384    CloseHandle(hEventTimeout);
    385    return hr;
    386}
    387
    388STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
    389    VSS_ID SnapshotSetId, LONG lSnapshotsCount)
    390{
    391    return S_OK;
    392}
    393
    394STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
    395{
    396    return S_OK;
    397}
    398
    399STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
    400{
    401    return S_OK;
    402}
    403
    404STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
    405{
    406    return S_OK;
    407}
    408
    409/*
    410 * IVssProviderNotifications methods
    411 */
    412
    413STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
    414{
    415    return S_OK;
    416}
    417
    418STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
    419{
    420    return S_OK;
    421}
    422
    423
    424/*
    425 * CQGAVssProviderFactory class
    426 */
    427
    428class CQGAVssProviderFactory : public IClassFactory
    429{
    430public:
    431    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
    432    STDMETHODIMP_(ULONG) AddRef();
    433    STDMETHODIMP_(ULONG) Release();
    434    STDMETHODIMP CreateInstance(
    435        IUnknown *pUnknownOuter, REFIID iid, void **ppv);
    436    STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
    437
    438    CQGAVssProviderFactory();
    439    ~CQGAVssProviderFactory();
    440
    441private:
    442    long m_nRefCount;
    443};
    444
    445CQGAVssProviderFactory::CQGAVssProviderFactory()
    446{
    447    m_nRefCount = 0;
    448    LockModule(TRUE);
    449}
    450
    451CQGAVssProviderFactory::~CQGAVssProviderFactory()
    452{
    453    LockModule(FALSE);
    454}
    455
    456STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
    457{
    458    if (riid == IID_IUnknown || riid == IID_IClassFactory) {
    459        *ppv = static_cast<void*>(this);
    460        AddRef();
    461        return S_OK;
    462    }
    463    *ppv = NULL;
    464    return E_NOINTERFACE;
    465}
    466
    467STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
    468{
    469    return InterlockedIncrement(&m_nRefCount);
    470}
    471
    472STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
    473{
    474    long nRefCount = InterlockedDecrement(&m_nRefCount);
    475    if (m_nRefCount == 0) {
    476        delete this;
    477    }
    478    return nRefCount;
    479}
    480
    481STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
    482    IUnknown *pUnknownOuter, REFIID iid, void **ppv)
    483{
    484    CQGAVssProvider *pObj;
    485
    486    if (pUnknownOuter) {
    487        return CLASS_E_NOAGGREGATION;
    488    }
    489    try {
    490        pObj = new CQGAVssProvider;
    491    } catch (...) {
    492        return E_OUTOFMEMORY;
    493    }
    494    HRESULT hr = pObj->QueryInterface(iid, ppv);
    495    if (FAILED(hr)) {
    496        delete pObj;
    497    }
    498    return hr;
    499}
    500
    501
    502/*
    503 * DLL functions
    504 */
    505
    506STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
    507{
    508    CQGAVssProviderFactory *factory;
    509    try {
    510        factory = new CQGAVssProviderFactory;
    511    } catch (...) {
    512        return E_OUTOFMEMORY;
    513    }
    514    factory->AddRef();
    515    HRESULT hr = factory->QueryInterface(riid, ppv);
    516    factory->Release();
    517    return hr;
    518}
    519
    520STDAPI DllCanUnloadNow()
    521{
    522    return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
    523}
    524
    525EXTERN_C
    526BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
    527{
    528    if (dwReason == DLL_PROCESS_ATTACH) {
    529        g_hinstDll = hinstDll;
    530        DisableThreadLibraryCalls(hinstDll);
    531    }
    532    return TRUE;
    533}