From nobody Wed Jun 26 12:38:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548716144146281.3162680884409; Mon, 28 Jan 2019 14:55:44 -0800 (PST) Received: from localhost ([127.0.0.1]:39750 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1goFod-0007hg-1F for importer@patchew.org; Mon, 28 Jan 2019 17:55:43 -0500 Received: from eggs.gnu.org ([209.51.188.92]:46976) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1goFcA-0006i3-4b for qemu-devel@nongnu.org; Mon, 28 Jan 2019 17:42:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1goFRS-0006Ji-LO for qemu-devel@nongnu.org; Mon, 28 Jan 2019 17:31:48 -0500 Received: from mail-it1-x144.google.com ([2607:f8b0:4864:20::144]:53020) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1goFRQ-0006Fk-Hx for qemu-devel@nongnu.org; Mon, 28 Jan 2019 17:31:45 -0500 Received: by mail-it1-x144.google.com with SMTP id d11so1189498itf.2 for ; Mon, 28 Jan 2019 14:31:39 -0800 (PST) Received: from localhost.localdomain (50-250-249-65-static.hfc.comcastbusiness.net. [50.250.249.65]) by smtp.gmail.com with ESMTPSA id n129sm479476itb.20.2019.01.28.14.31.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 28 Jan 2019 14:31:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=scalecomputing-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=AeDc9QUf5AUQEHfYufjklrDun3MIa2iu7hcMIUT1hU4=; b=JkMuvvMKEt9ymldZ3nE+JZf9K72UB7Z8svI3GgUVBdFc9eYI5yKsP35oBq0Enarufy kCSDyaNs0jbhlY59FoN+ZOXU47miaH/c1Q8y68B8Sf2x2J0f743+1aNNhtMGiQkbLCSW qazV0qJlNpuNFAV5AHylMAfBoZRY6KXy2bsEu08OHkbQ6HvQQn/eqY9I9sntAgL6xIvK CHJL5rkcaQ99BU0rG00KWvdtXmdQj4GyUn7v9rFANBu5gf5kOg9AJU+eTA+aMBth1aq2 FOKKlfmg/ulob795D3BJsiU6BRIMzhvgSM7abX+c4eyC3+sZCGkAKoKD5yEx48yzGoRZ W1kQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=AeDc9QUf5AUQEHfYufjklrDun3MIa2iu7hcMIUT1hU4=; b=qH9JMZAosNQWvTwm6+m12VO2dHiz9fbxX/SdHWr/m72m7MXJZCcAC2kjQyXjDwW3Si 3YV82G6zdpM432ZSljmPAmd6b5DRqp2y4tWAzgX0b6XkhOblsmSIstqGWflSPbRf0kdo RwukbFJ8InYAEgwvE0Gaz++RW88iCUg+08kx9eje4xNDfAVywLiL0qygjJNx2DelSdxF Mv01j4xypJQGwYW01gpWiCaXFwXYxRqmJ74KLPEwrsmSxKQYeXvJ6Eu9srZEHYGz5jOw vWDTnuuxCgwRjRcSP4eofSsAdmk4gJw/GbR14JDRIJOw7zoZiBoO8sLGoLGKKFFx5x2m hAaQ== X-Gm-Message-State: AJcUuke+9om7Cb/evhtjxFyYTWOG7SQMoIlpxSrV2STIA7pTSwh241FT LdXfWGbX/qm53HgQpPNUNUG4L6wD7G0j7NB8 X-Google-Smtp-Source: ALg8bN5QCa2vqvxEdu9QCS4DngOKKF6C9Ub4fE1SzUB0RFqJ3lC8v95NF1HJ+Xf4kkSOZQcIq/TCzA== X-Received: by 2002:a24:b8c6:: with SMTP id m189mr10672712ite.72.1548714697809; Mon, 28 Jan 2019 14:31:37 -0800 (PST) From: mhines@scalecomputing.com To: qemu-devel@nongnu.org Date: Mon, 28 Jan 2019 14:30:56 -0800 Message-Id: <20190128223056.19452-1-mhines@scalecomputing.com> X-Mailer: git-send-email 2.11.0.windows.1 In-Reply-To: <20190114090324.16176-1-mhines@scalecomputing.com> References: <20190114090324.16176-1-mhines@scalecomputing.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::144 Subject: [Qemu-devel] [PATCH v3] QGA: Fix guest-get-fsinfo PCI address collection in Windows X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matt Hines , Michael Roth Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Matt Hines The Windows QEMU guest agent erroneously tries to collect PCI information directly from the physical drive. However, windows stores SCSI/IDE informat= ion with the drive and PCI information with the underlying storage controller This changes get_pci_info to use the physical drive's underlying storage controller to get PCI information. * Additionally Fixes incorrect size being passed to DeviceIoControl when getting volume extents. Can occasionally crash the guest agent Signed-off-by: Matt Hines --- configure | 2 +- qga/commands-win32.c | 305 +++++++++++++++++++++++++++++++++--------------= ---- 2 files changed, 199 insertions(+), 108 deletions(-) diff --git a/configure b/configure index 5b1d83ea26..46f21c089f 100755 --- a/configure +++ b/configure @@ -4694,7 +4694,7 @@ int main(void) { EOF if compile_prog "" "" ; then guest_agent_ntddscsi=3Dyes - libs_qga=3D"-lsetupapi $libs_qga" + libs_qga=3D"-lsetupapi -lcfgmgr32 $libs_qga" fi fi =20 diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 62e1b51dfe..5f8e797032 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #endif #include @@ -491,56 +492,29 @@ static GuestDiskBusType find_bus_type(STORAGE_BUS_TYP= E bus) return win2qemu[(int)bus]; } =20 -/* XXX: The following function is BROKEN! - * - * It does not work and probably has never worked. When we query for list = of - * disks we get cryptic names like "\Device\0000001d" instead of - * "\PhysicalDriveX" or "\HarddiskX". Whether the names can be translated = one - * way or the other for comparison is an open question. - * - * When we query volume names (the original version) we are able to match = those - * but then the property queries report error "Invalid function". (duh!) - */ - -/* -DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, - 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, - 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -*/ DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, + 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, + 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); =20 - -static GuestPCIAddress *get_pci_info(char *guid, Error **errp) +static GuestPCIAddress *get_pci_info(int number, Error **errp) { HDEVINFO dev_info; SP_DEVINFO_DATA dev_info_data; - DWORD size =3D 0; + SP_DEVICE_INTERFACE_DATA dev_iface_data; + HANDLE dev_file; int i; - char dev_name[MAX_PATH]; - char *buffer =3D NULL; GuestPCIAddress *pci =3D NULL; - char *name =3D NULL; bool partial_pci =3D false; + pci =3D g_malloc0(sizeof(*pci)); pci->domain =3D -1; pci->slot =3D -1; pci->function =3D -1; pci->bus =3D -1; =20 - if (g_str_has_prefix(guid, "\\\\.\\") || - g_str_has_prefix(guid, "\\\\?\\")) { - name =3D g_strdup(guid + 4); - } else { - name =3D g_strdup(guid); - } - - if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) { - error_setg_win32(errp, GetLastError(), "failed to get dos device n= ame"); - goto out; - } - dev_info =3D SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (dev_info =3D=3D INVALID_HANDLE_VALUE) { @@ -550,90 +524,208 @@ static GuestPCIAddress *get_pci_info(char *guid, Err= or **errp) =20 g_debug("enumerating devices"); dev_info_data.cbSize =3D sizeof(SP_DEVINFO_DATA); + dev_iface_data.cbSize =3D sizeof(SP_DEVICE_INTERFACE_DATA); for (i =3D 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++)= { - DWORD addr, bus, slot, data, size2; - int func, dev; - while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_PHYSICAL_DEVICE_OBJECT_N= AME, - &data, (PBYTE)buffer, size, - &size2)) { - size =3D MAX(size, size2); - if (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) { - g_free(buffer); - /* Double the size to avoid problems on - * W2k MBCS systems per KB 888609. - * https://support.microsoft.com/en-us/kb/259695 */ - buffer =3D g_malloc(size * 2); - } else { + PSP_DEVICE_INTERFACE_DETAIL_DATA pdev_iface_detail_data =3D NULL; + STORAGE_DEVICE_NUMBER sdn; + char *parent_dev_id =3D NULL; + HDEVINFO parent_dev_info; + SP_DEVINFO_DATA parent_dev_info_data; + DWORD j; + DWORD size =3D 0; + + g_debug("getting device path"); + if (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, + &GUID_DEVINTERFACE_DISK, 0, + &dev_iface_data)) { + while (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_d= ata, + pdev_iface_detail_data, + size, &size, + &dev_info_data)) { + if (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) { + pdev_iface_detail_data =3D g_malloc(size); + pdev_iface_detail_data->cbSize =3D + sizeof(*pdev_iface_detail_data); + } else { + error_setg_win32(errp, GetLastError(), + "failed to get device interfaces"); + goto free_dev_info; + } + } + + dev_file =3D CreateFile(pdev_iface_detail_data->DevicePath, 0, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, + NULL); + g_free(pdev_iface_detail_data); + + if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER, + NULL, 0, &sdn, sizeof(sdn), &size, NULL))= { + CloseHandle(dev_file); error_setg_win32(errp, GetLastError(), - "failed to get device name"); + "failed to get device slot number"); goto free_dev_info; } - } =20 - if (g_strcmp0(buffer, dev_name)) { - continue; + CloseHandle(dev_file); + if (sdn.DeviceNumber !=3D number) { + continue; + } + } else { + error_setg_win32(errp, GetLastError(), + "failed to get device interfaces"); + goto free_dev_info; } - g_debug("found device %s", dev_name); =20 - /* There is no need to allocate buffer in the next functions. The = size - * is known and ULONG according to - * https://support.microsoft.com/en-us/kb/253232 - * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543= 095(v=3Dvs.85).aspx - */ - if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) { - debug_error("failed to get bus"); - bus =3D -1; - partial_pci =3D true; + g_debug("found device slot %d. Getting storage controller", number= ); + { + CONFIGRET cr; + DEVINST dev_inst, parent_dev_inst; + ULONG dev_id_size =3D 0; + + size =3D 0; + while (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data, + parent_dev_id, size, &size)= ) { + if (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) { + parent_dev_id =3D g_malloc(size); + } else { + error_setg_win32(errp, GetLastError(), + "failed to get device instance ID"); + goto out; + } + } + + /* + * CM API used here as opposed to + * SetupDiGetDeviceProperty(..., DEVPKEY_Device_Parent, ...) + * which exports are only available in mingw-w64 6+ + */ + cr =3D CM_Locate_DevInst(&dev_inst, parent_dev_id, 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Locate_DevInst failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get device instance"); + goto out; + } + cr =3D CM_Get_Parent(&parent_dev_inst, dev_inst, 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Get_Parent failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get parent device instance"); + goto out; + } + + cr =3D CM_Get_Device_ID_Size(&dev_id_size, parent_dev_inst, 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Get_Device_ID_Size failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get parent device ID length"); + goto out; + } + + ++dev_id_size; + if (dev_id_size > size) { + g_free(parent_dev_id); + parent_dev_id =3D g_malloc(dev_id_size); + } + + cr =3D CM_Get_Device_ID(parent_dev_inst, parent_dev_id, dev_id= _size, + 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Get_Device_ID failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get parent device ID"); + goto out; + } } =20 - /* The function retrieves the device's address. This value will be - * transformed into device function and number */ - if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) { - debug_error("failed to get address"); - addr =3D -1; - partial_pci =3D true; + g_debug("querying storage controller %s for PCI information", + parent_dev_id); + parent_dev_info =3D + SetupDiGetClassDevs(&GUID_DEVINTERFACE_STORAGEPORT, parent_dev= _id, + NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFAC= E); + g_free(parent_dev_id); + + if (parent_dev_info =3D=3D INVALID_HANDLE_VALUE) { + error_setg_win32(errp, GetLastError(), + "failed to get parent device"); + goto out; } =20 - /* This call returns UINumber of DEVICE_CAPABILITIES structure. - * This number is typically a user-perceived slot number. */ - if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) { - debug_error("failed to get slot"); - slot =3D -1; - partial_pci =3D true; + parent_dev_info_data.cbSize =3D sizeof(SP_DEVINFO_DATA); + if (!SetupDiEnumDeviceInfo(parent_dev_info, 0, &parent_dev_info_da= ta)) { + error_setg_win32(errp, GetLastError(), + "failed to get parent device data"); + goto out; } =20 - /* SetupApi gives us the same information as driver with - * IoGetDeviceProperty. According to Microsoft - * https://support.microsoft.com/en-us/kb/253232 - * FunctionNumber =3D (USHORT)((propertyAddress) & 0x0000FFFF); - * DeviceNumber =3D (USHORT)(((propertyAddress) >> 16) & 0x0000FFF= F); - * SPDRP_ADDRESS is propertyAddress, so we do the same.*/ - - if (partial_pci) { - pci->domain =3D -1; - pci->slot =3D -1; - pci->function =3D -1; - pci->bus =3D -1; - } else { - func =3D ((int) addr =3D=3D -1) ? -1 : addr & 0x0000FFFF; - dev =3D ((int) addr =3D=3D -1) ? -1 : (addr >> 16) & 0x0000FFF= F; - pci->domain =3D dev; - pci->slot =3D (int) slot; - pci->function =3D func; - pci->bus =3D (int) bus; + for (j =3D 0; + SetupDiEnumDeviceInfo(parent_dev_info, j, &parent_dev_info_da= ta); + j++) { + DWORD addr, bus, slot, type; + int func, dev; + + /* There is no need to allocate buffer in the next functions. = The size + * is known and ULONG according to + * https://msdn.microsoft.com/en-us/library/windows/hardware/ff= 543095(v=3Dvs.85).aspx + */ + if (!SetupDiGetDeviceRegistryProperty( + parent_dev_info, &parent_dev_info_data, SPDRP_BUSNUMBER, + &type, (PBYTE)&bus, size, NULL)) { + debug_error("failed to get PCI bus"); + bus =3D -1; + partial_pci =3D true; + } + + /* The function retrieves the device's address. This value wil= l be + * transformed into device function and number */ + if (!SetupDiGetDeviceRegistryProperty( + parent_dev_info, &parent_dev_info_data, SPDRP_ADDRESS, + &type, (PBYTE)&addr, size, NULL)) { + debug_error("failed to get PCI address"); + addr =3D -1; + partial_pci =3D true; + } + + /* This call returns UINumber of DEVICE_CAPABILITIES structure. + * This number is typically a user-perceived slot number. */ + if (!SetupDiGetDeviceRegistryProperty( + parent_dev_info, &parent_dev_info_data, SPDRP_UI_NUMBE= R, + &type, (PBYTE)&slot, size, NULL)) { + debug_error("failed to get PCI slot"); + slot =3D -1; + partial_pci =3D true; + } + + /* SetupApi gives us the same information as driver with + * IoGetDeviceProperty. According to Microsoft + * https://docs.microsoft.com/en-us/windows/desktop/api/setupap= i/nf-setupapi-setupdigetdeviceregistrypropertya + * FunctionNumber =3D (USHORT)((propertyAddress) & 0x0000FFFF); + * DeviceNumber =3D (USHORT)(((propertyAddress) >> 16) & 0x0000= FFFF); + * SPDRP_ADDRESS is propertyAddress, so we do the same.*/ + + if (partial_pci) { + pci->domain =3D -1; + pci->slot =3D -1; + pci->function =3D -1; + pci->bus =3D -1; + continue; + } else { + func =3D ((int)addr =3D=3D -1) ? -1 : addr & 0x0000FFFF; + dev =3D ((int)addr =3D=3D -1) ? -1 : (addr >> 16) & 0x0000= FFFF; + pci->domain =3D dev; + pci->slot =3D (int)slot; + pci->function =3D func; + pci->bus =3D (int)bus; + break; + } } + SetupDiDestroyDeviceInfoList(parent_dev_info); break; } =20 free_dev_info: SetupDiDestroyDeviceInfoList(dev_info); out: - g_free(buffer); - g_free(name); return pci; } =20 @@ -691,7 +783,8 @@ out_free: return; } =20 -static void get_single_disk_info(GuestDiskAddress *disk, Error **errp) +static void get_single_disk_info(int disk_number, + GuestDiskAddress *disk, Error **errp) { SCSI_ADDRESS addr, *scsi_ad; DWORD len; @@ -720,7 +813,7 @@ static void get_single_disk_info(GuestDiskAddress *disk= , Error **errp) * if that doesn't hold since that suggests some other unexpected * breakage */ - disk->pci_controller =3D get_pci_info(disk->dev, &local_err); + disk->pci_controller =3D get_pci_info(disk_number, &local_err); if (local_err) { error_propagate(errp, local_err); goto err_close; @@ -736,7 +829,7 @@ static void get_single_disk_info(GuestDiskAddress *disk= , Error **errp) /* We are able to use the same ioctls for different bus types * according to Microsoft docs * https://technet.microsoft.com/en-us/library/ee851589(v=3Dws.10)= .aspx */ - g_debug("getting pci-controller info"); + g_debug("getting SCSI info"); if (DeviceIoControl(disk_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_= ad, sizeof(SCSI_ADDRESS), &len, NULL)) { disk->unit =3D addr.Lun; @@ -784,12 +877,10 @@ static GuestDiskAddressList *build_guest_disk_info(ch= ar *guid, Error **errp) size =3D sizeof(VOLUME_DISK_EXTENTS); extents =3D g_malloc0(size); if (!DeviceIoControl(vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, - 0, extents, size, NULL, NULL)) { + 0, extents, size, &size, NULL)) { DWORD last_err =3D GetLastError(); if (last_err =3D=3D ERROR_MORE_DATA) { /* Try once more with big enough buffer */ - size =3D sizeof(VOLUME_DISK_EXTENTS) - + extents->NumberOfDiskExtents*sizeof(DISK_EXTENT); g_free(extents); extents =3D g_malloc0(size); if (!DeviceIoControl( @@ -805,7 +896,7 @@ static GuestDiskAddressList *build_guest_disk_info(char= *guid, Error **errp) disk =3D g_malloc0(sizeof(GuestDiskAddress)); disk->has_dev =3D true; disk->dev =3D g_strdup(name); - get_single_disk_info(disk, &local_err); + get_single_disk_info(0xffffffff, disk, &local_err); if (local_err) { g_debug("failed to get disk info, ignoring error: %s", error_get_pretty(local_err)); @@ -839,9 +930,9 @@ static GuestDiskAddressList *build_guest_disk_info(char= *guid, Error **errp) */ disk->has_dev =3D true; disk->dev =3D g_strdup_printf("\\\\.\\PhysicalDrive%lu", - extents->Extents[i].DiskNumber); + extents->Extents[i].DiskNumber); =20 - get_single_disk_info(disk, &local_err); + get_single_disk_info(extents->Extents[i].DiskNumber, disk, &local_= err); if (local_err) { error_propagate(errp, local_err); goto out; --=20 2.11.0.windows.1