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

requester.cpp (17673B)


      1/*
      2 * QEMU Guest Agent win32 VSS Requester 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 "requester.h"
     16#include "install.h"
     17#include <inc/win2003/vswriter.h>
     18#include <inc/win2003/vsbackup.h>
     19
     20/* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
     21#define VSS_TIMEOUT_FREEZE_MSEC 60000
     22
     23/* Call QueryStatus every 10 ms while waiting for frozen event */
     24#define VSS_TIMEOUT_EVENT_MSEC 10
     25
     26#define err_set(e, err, fmt, ...)                                           \
     27    ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
     28                                   err, fmt, ## __VA_ARGS__))
     29/* Bad idea, works only when (e)->errp != NULL: */
     30#define err_is_set(e) ((e)->errp && *(e)->errp)
     31/* To lift this restriction, error_propagate(), like we do in QEMU code */
     32
     33/* Handle to VSSAPI.DLL */
     34static HMODULE hLib;
     35
     36/* Functions in VSSAPI.DLL */
     37typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
     38    OUT IVssBackupComponents**);
     39typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
     40static t_CreateVssBackupComponents pCreateVssBackupComponents;
     41static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
     42
     43/* Variables used while applications and filesystes are frozen by VSS */
     44static struct QGAVSSContext {
     45    IVssBackupComponents *pVssbc;  /* VSS requester interface */
     46    IVssAsync *pAsyncSnapshot;     /* async info of VSS snapshot operation */
     47    HANDLE hEventFrozen;           /* notify fs/writer freeze from provider */
     48    HANDLE hEventThaw;             /* request provider to thaw */
     49    HANDLE hEventTimeout;          /* notify timeout in provider */
     50    int cFrozenVols;               /* number of frozen volumes */
     51} vss_ctx;
     52
     53STDAPI requester_init(void)
     54{
     55    COMInitializer initializer; /* to call CoInitializeSecurity */
     56    HRESULT hr = CoInitializeSecurity(
     57        NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
     58        RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
     59    if (FAILED(hr)) {
     60        fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr);
     61        return hr;
     62    }
     63
     64    hLib = LoadLibraryA("VSSAPI.DLL");
     65    if (!hLib) {
     66        fprintf(stderr, "failed to load VSSAPI.DLL\n");
     67        return HRESULT_FROM_WIN32(GetLastError());
     68    }
     69
     70    pCreateVssBackupComponents = (t_CreateVssBackupComponents)
     71        GetProcAddress(hLib,
     72#ifdef _WIN64 /* 64bit environment */
     73        "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
     74#else /* 32bit environment */
     75        "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
     76#endif
     77        );
     78    if (!pCreateVssBackupComponents) {
     79        fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
     80        return HRESULT_FROM_WIN32(GetLastError());
     81    }
     82
     83    pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
     84        GetProcAddress(hLib, "VssFreeSnapshotProperties");
     85    if (!pVssFreeSnapshotProperties) {
     86        fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
     87        return HRESULT_FROM_WIN32(GetLastError());
     88    }
     89
     90    return S_OK;
     91}
     92
     93static void requester_cleanup(void)
     94{
     95    if (vss_ctx.hEventFrozen) {
     96        CloseHandle(vss_ctx.hEventFrozen);
     97        vss_ctx.hEventFrozen = NULL;
     98    }
     99    if (vss_ctx.hEventThaw) {
    100        CloseHandle(vss_ctx.hEventThaw);
    101        vss_ctx.hEventThaw = NULL;
    102    }
    103    if (vss_ctx.hEventTimeout) {
    104        CloseHandle(vss_ctx.hEventTimeout);
    105        vss_ctx.hEventTimeout = NULL;
    106    }
    107    if (vss_ctx.pAsyncSnapshot) {
    108        vss_ctx.pAsyncSnapshot->Release();
    109        vss_ctx.pAsyncSnapshot = NULL;
    110    }
    111    if (vss_ctx.pVssbc) {
    112        vss_ctx.pVssbc->Release();
    113        vss_ctx.pVssbc = NULL;
    114    }
    115    vss_ctx.cFrozenVols = 0;
    116}
    117
    118STDAPI requester_deinit(void)
    119{
    120    requester_cleanup();
    121
    122    pCreateVssBackupComponents = NULL;
    123    pVssFreeSnapshotProperties = NULL;
    124    if (hLib) {
    125        FreeLibrary(hLib);
    126        hLib = NULL;
    127    }
    128
    129    return S_OK;
    130}
    131
    132static HRESULT WaitForAsync(IVssAsync *pAsync)
    133{
    134    HRESULT ret, hr;
    135
    136    do {
    137        hr = pAsync->Wait();
    138        if (FAILED(hr)) {
    139            ret = hr;
    140            break;
    141        }
    142        hr = pAsync->QueryStatus(&ret, NULL);
    143        if (FAILED(hr)) {
    144            ret = hr;
    145            break;
    146        }
    147    } while (ret == VSS_S_ASYNC_PENDING);
    148
    149    return ret;
    150}
    151
    152static void AddComponents(ErrorSet *errset)
    153{
    154    unsigned int cWriters, i;
    155    VSS_ID id, idInstance, idWriter;
    156    BSTR bstrWriterName = NULL;
    157    VSS_USAGE_TYPE usage;
    158    VSS_SOURCE_TYPE source;
    159    unsigned int cComponents, c1, c2, j;
    160    COMPointer<IVssExamineWriterMetadata> pMetadata;
    161    COMPointer<IVssWMComponent> pComponent;
    162    PVSSCOMPONENTINFO info;
    163    HRESULT hr;
    164
    165    hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
    166    if (FAILED(hr)) {
    167        err_set(errset, hr, "failed to get writer metadata count");
    168        goto out;
    169    }
    170
    171    for (i = 0; i < cWriters; i++) {
    172        hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
    173        if (FAILED(hr)) {
    174            err_set(errset, hr, "failed to get writer metadata of %d/%d",
    175                             i, cWriters);
    176            goto out;
    177        }
    178
    179        hr = pMetadata->GetIdentity(&idInstance, &idWriter,
    180                                    &bstrWriterName, &usage, &source);
    181        if (FAILED(hr)) {
    182            err_set(errset, hr, "failed to get identity of writer %d/%d",
    183                             i, cWriters);
    184            goto out;
    185        }
    186
    187        hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
    188        if (FAILED(hr)) {
    189            err_set(errset, hr, "failed to get file counts of %S",
    190                             bstrWriterName);
    191            goto out;
    192        }
    193
    194        for (j = 0; j < cComponents; j++) {
    195            hr = pMetadata->GetComponent(j, pComponent.replace());
    196            if (FAILED(hr)) {
    197                err_set(errset, hr,
    198                                 "failed to get component %d/%d of %S",
    199                                 j, cComponents, bstrWriterName);
    200                goto out;
    201            }
    202
    203            hr = pComponent->GetComponentInfo(&info);
    204            if (FAILED(hr)) {
    205                err_set(errset, hr,
    206                                 "failed to get component info %d/%d of %S",
    207                                 j, cComponents, bstrWriterName);
    208                goto out;
    209            }
    210
    211            if (info->bSelectable) {
    212                hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
    213                                                  info->type,
    214                                                  info->bstrLogicalPath,
    215                                                  info->bstrComponentName);
    216                if (FAILED(hr)) {
    217                    err_set(errset, hr, "failed to add component %S(%S)",
    218                                     info->bstrComponentName, bstrWriterName);
    219                    goto out;
    220                }
    221            }
    222            SysFreeString(bstrWriterName);
    223            bstrWriterName = NULL;
    224            pComponent->FreeComponentInfo(info);
    225            info = NULL;
    226        }
    227    }
    228out:
    229    if (bstrWriterName) {
    230        SysFreeString(bstrWriterName);
    231    }
    232    if (pComponent && info) {
    233        pComponent->FreeComponentInfo(info);
    234    }
    235}
    236
    237void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
    238{
    239    COMPointer<IVssAsync> pAsync;
    240    HANDLE volume;
    241    HRESULT hr;
    242    LONG ctx;
    243    GUID guidSnapshotSet = GUID_NULL;
    244    SECURITY_DESCRIPTOR sd;
    245    SECURITY_ATTRIBUTES sa;
    246    WCHAR short_volume_name[64], *display_name = short_volume_name;
    247    DWORD wait_status;
    248    int num_fixed_drives = 0, i;
    249    int num_mount_points = 0;
    250
    251    if (vss_ctx.pVssbc) { /* already frozen */
    252        *num_vols = 0;
    253        return;
    254    }
    255
    256    CoInitialize(NULL);
    257
    258    /* Allow unrestricted access to events */
    259    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
    260    SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
    261    sa.nLength = sizeof(sa);
    262    sa.lpSecurityDescriptor = &sd;
    263    sa.bInheritHandle = FALSE;
    264
    265    vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
    266    if (!vss_ctx.hEventFrozen) {
    267        err_set(errset, GetLastError(), "failed to create event %s",
    268                EVENT_NAME_FROZEN);
    269        goto out;
    270    }
    271    vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
    272    if (!vss_ctx.hEventThaw) {
    273        err_set(errset, GetLastError(), "failed to create event %s",
    274                EVENT_NAME_THAW);
    275        goto out;
    276    }
    277    vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
    278    if (!vss_ctx.hEventTimeout) {
    279        err_set(errset, GetLastError(), "failed to create event %s",
    280                EVENT_NAME_TIMEOUT);
    281        goto out;
    282    }
    283
    284    assert(pCreateVssBackupComponents != NULL);
    285    hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
    286    if (FAILED(hr)) {
    287        err_set(errset, hr, "failed to create VSS backup components");
    288        goto out;
    289    }
    290
    291    hr = vss_ctx.pVssbc->InitializeForBackup();
    292    if (FAILED(hr)) {
    293        err_set(errset, hr, "failed to initialize for backup");
    294        goto out;
    295    }
    296
    297    hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false);
    298    if (FAILED(hr)) {
    299        err_set(errset, hr, "failed to set backup state");
    300        goto out;
    301    }
    302
    303    /*
    304     * Currently writable snapshots are not supported.
    305     * To prevent the final commit (which requires to write to snapshots),
    306     * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
    307     */
    308    ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
    309        VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
    310    hr = vss_ctx.pVssbc->SetContext(ctx);
    311    if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
    312        /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
    313        ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
    314        hr = vss_ctx.pVssbc->SetContext(ctx);
    315    }
    316    if (FAILED(hr)) {
    317        err_set(errset, hr, "failed to set backup context");
    318        goto out;
    319    }
    320
    321    hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
    322    if (SUCCEEDED(hr)) {
    323        hr = WaitForAsync(pAsync);
    324    }
    325    if (FAILED(hr)) {
    326        err_set(errset, hr, "failed to gather writer metadata");
    327        goto out;
    328    }
    329
    330    AddComponents(errset);
    331    if (err_is_set(errset)) {
    332        goto out;
    333    }
    334
    335    hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
    336    if (FAILED(hr)) {
    337        err_set(errset, hr, "failed to start snapshot set");
    338        goto out;
    339    }
    340
    341    if (mountpoints) {
    342        PWCHAR volume_name_wchar;
    343        for (volList *list = (volList *)mountpoints; list; list = list->next) {
    344            size_t len = strlen(list->value) + 1;
    345            size_t converted = 0;
    346            VSS_ID pid;
    347
    348            volume_name_wchar = new wchar_t[len];
    349            mbstowcs_s(&converted, volume_name_wchar, len,
    350                       list->value, _TRUNCATE);
    351
    352            hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
    353                                                  g_gProviderId, &pid);
    354            if (FAILED(hr)) {
    355                err_set(errset, hr, "failed to add %S to snapshot set",
    356                        volume_name_wchar);
    357                delete volume_name_wchar;
    358                goto out;
    359            }
    360            num_mount_points++;
    361
    362            delete volume_name_wchar;
    363        }
    364
    365        if (num_mount_points == 0) {
    366            /* If there is no valid mount points, just exit. */
    367            goto out;
    368        }
    369    }
    370
    371    if (!mountpoints) {
    372        volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
    373        if (volume == INVALID_HANDLE_VALUE) {
    374            err_set(errset, hr, "failed to find first volume");
    375            goto out;
    376        }
    377
    378        for (;;) {
    379            if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
    380                VSS_ID pid;
    381                hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
    382                                                      g_gProviderId, &pid);
    383                if (FAILED(hr)) {
    384                    WCHAR volume_path_name[PATH_MAX];
    385                    if (GetVolumePathNamesForVolumeNameW(
    386                            short_volume_name, volume_path_name,
    387                            sizeof(volume_path_name), NULL) &&
    388                            *volume_path_name) {
    389                        display_name = volume_path_name;
    390                    }
    391                    err_set(errset, hr, "failed to add %S to snapshot set",
    392                            display_name);
    393                    FindVolumeClose(volume);
    394                    goto out;
    395                }
    396                num_fixed_drives++;
    397            }
    398            if (!FindNextVolumeW(volume, short_volume_name,
    399                                 sizeof(short_volume_name))) {
    400                FindVolumeClose(volume);
    401                break;
    402            }
    403        }
    404
    405        if (num_fixed_drives == 0) {
    406            goto out; /* If there is no fixed drive, just exit. */
    407        }
    408    }
    409
    410    hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
    411    if (SUCCEEDED(hr)) {
    412        hr = WaitForAsync(pAsync);
    413    }
    414    if (FAILED(hr)) {
    415        err_set(errset, hr, "failed to prepare for backup");
    416        goto out;
    417    }
    418
    419    hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
    420    if (SUCCEEDED(hr)) {
    421        hr = WaitForAsync(pAsync);
    422    }
    423    if (FAILED(hr)) {
    424        err_set(errset, hr, "failed to gather writer status");
    425        goto out;
    426    }
    427
    428    /*
    429     * Start VSS quiescing operations.
    430     * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
    431     * after the applications and filesystems are frozen.
    432     */
    433    hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
    434    if (FAILED(hr)) {
    435        err_set(errset, hr, "failed to do snapshot set");
    436        goto out;
    437    }
    438
    439    /* Need to call QueryStatus several times to make VSS provider progress */
    440    for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
    441        HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
    442        if (FAILED(hr2)) {
    443            err_set(errset, hr, "failed to do snapshot set");
    444            goto out;
    445        }
    446        if (hr != VSS_S_ASYNC_PENDING) {
    447            err_set(errset, E_FAIL,
    448                    "DoSnapshotSet exited without Frozen event");
    449            goto out;
    450        }
    451        wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
    452                                          VSS_TIMEOUT_EVENT_MSEC);
    453        if (wait_status != WAIT_TIMEOUT) {
    454            break;
    455        }
    456    }
    457
    458    if (wait_status == WAIT_TIMEOUT) {
    459        err_set(errset, E_FAIL,
    460                "timeout when try to receive Frozen event from VSS provider");
    461        /* If we are here, VSS had timeout.
    462         * Don't call AbortBackup, just return directly.
    463         */
    464        goto out1;
    465    }
    466
    467    if (wait_status != WAIT_OBJECT_0) {
    468        err_set(errset, E_FAIL,
    469                "couldn't receive Frozen event from VSS provider");
    470        goto out;
    471    }
    472
    473    if (mountpoints) {
    474        *num_vols = vss_ctx.cFrozenVols = num_mount_points;
    475    } else {
    476        *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
    477    }
    478
    479    return;
    480
    481out:
    482    if (vss_ctx.pVssbc) {
    483        vss_ctx.pVssbc->AbortBackup();
    484    }
    485
    486out1:
    487    requester_cleanup();
    488    CoUninitialize();
    489}
    490
    491
    492void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
    493{
    494    COMPointer<IVssAsync> pAsync;
    495
    496    if (!vss_ctx.hEventThaw) {
    497        /*
    498         * In this case, DoSnapshotSet is aborted or not started,
    499         * and no volumes must be frozen. We return without an error.
    500         */
    501        *num_vols = 0;
    502        return;
    503    }
    504
    505    /* Tell the provider that the snapshot is finished. */
    506    SetEvent(vss_ctx.hEventThaw);
    507
    508    assert(vss_ctx.pVssbc);
    509    assert(vss_ctx.pAsyncSnapshot);
    510
    511    HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
    512    switch (hr) {
    513    case VSS_S_ASYNC_FINISHED:
    514        hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
    515        if (SUCCEEDED(hr)) {
    516            hr = WaitForAsync(pAsync);
    517        }
    518        if (FAILED(hr)) {
    519            err_set(errset, hr, "failed to complete backup");
    520        }
    521        break;
    522
    523    case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
    524        /*
    525         * On Windows earlier than 2008 SP2 which does not support
    526         * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
    527         * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
    528         * the system had been frozen until fsfreeze-thaw command was issued,
    529         * we ignore this error.
    530         */
    531        vss_ctx.pVssbc->AbortBackup();
    532        break;
    533
    534    case VSS_E_UNEXPECTED_PROVIDER_ERROR:
    535        if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
    536            err_set(errset, hr, "unexpected error in VSS provider");
    537            break;
    538        }
    539        /* fall through if hEventTimeout is signaled */
    540
    541    case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
    542        err_set(errset, hr, "couldn't hold writes: "
    543                "fsfreeze is limited up to 10 seconds");
    544        break;
    545
    546    default:
    547        err_set(errset, hr, "failed to do snapshot set");
    548    }
    549
    550    if (err_is_set(errset)) {
    551        vss_ctx.pVssbc->AbortBackup();
    552    }
    553    *num_vols = vss_ctx.cFrozenVols;
    554    requester_cleanup();
    555
    556    CoUninitialize();
    557    StopService();
    558}