From nobody Mon Dec 15 22:39:50 2025 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 1552926691507245.56048817026897; Mon, 18 Mar 2019 09:31:31 -0700 (PDT) Received: from localhost ([127.0.0.1]:44281 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h5vAe-0005gq-AC for importer@patchew.org; Mon, 18 Mar 2019 12:31:28 -0400 Received: from eggs.gnu.org ([209.51.188.92]:43969) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h5v4P-00012j-2I for qemu-devel@nongnu.org; Mon, 18 Mar 2019 12:25:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h5v4M-0002oG-Bo for qemu-devel@nongnu.org; Mon, 18 Mar 2019 12:25:00 -0400 Received: from mail-oi1-x22b.google.com ([2607:f8b0:4864:20::22b]:39961) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h5v4K-0002j7-T1 for qemu-devel@nongnu.org; Mon, 18 Mar 2019 12:24:57 -0400 Received: by mail-oi1-x22b.google.com with SMTP id k11so13532496oic.7 for ; Mon, 18 Mar 2019 09:24:50 -0700 (PDT) Received: from localhost (76-251-165-188.lightspeed.austtx.sbcglobal.net. [76.251.165.188]) by smtp.gmail.com with ESMTPSA id o84sm1526237oib.21.2019.03.18.09.24.47 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 18 Mar 2019 09:24:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=uAE7O7/pMcSAVK6ZKGYFhAM2oZUvPTw5he81ymdeeUo=; b=OsenleDxBrQYHinEyyEl4htBY3oOgNPcel8o3c3Vg0dtpL6zmRiJYVFrRDJOtwhOQL EpweHhkF4Qv294l29APl1bYZG4Vz2Q7vLENwq2OK1tgq+ZiSOd+iJbauldviyOEXkBbA FLdDmhAaZfOW4FM8qwSQMGS8XU8J2iwpHjJag/nyPOioVvSXFCJyHChs/jJik677/gKP SshnL3AG56DVNCconbHLCAbi4A6bkNBY18wZlGH6AJPXdlsJL+/U1xP1Iun+6qUY+Ec8 ucxpGGUdFhHhapvN0fdk4l4aKQkmusvNz7PShE4nvZpx6a31w4/yIJrj7Vw0bWym2byV nk5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=uAE7O7/pMcSAVK6ZKGYFhAM2oZUvPTw5he81ymdeeUo=; b=bA7J1hUElSBR9x16vMSADTcuHkFbdV7IQkfJlVi3Knd84cNiPxeEbA0e+kk1UlmgHe OqSelafTZgPi9PG/kxVWshIzVdDrLGZkAK+RLLOT1jv9YzYkJgzwKezYSZruZ+TPAAss DTvcrHdaLQ7cAMxmllGxfnAdSvkM1uQLjI5JUFHSjmpCo/wUUDOg6hWDBkyJcQUKBqwd qDnQtvyPrAfYfPeeYTgtFt+iLhB5BhDpeG3CA6KTe0+TgngiOK1FknaS69ASoEb2wKJK 4e5VIBOZJ3LVq53smfKPUq8ouEqJ5OClle9Nmv4C3f7N3WUZf3+GKz24xMGwWF7sjEsw qEcw== X-Gm-Message-State: APjAAAUvIk6k1/ghe6IdMDNtM+D5n9l88bmtrDeaZgTzFd8yAQ4plfLZ iYSsjhzVGAAlOu4HnyWp5xm61oqG X-Google-Smtp-Source: APXvYqz4ych6TNIOSGzzuwSlyOhp6juLujhmAhH1+k7+4ulLi13UpWUFuz3qZoTEPD2gkvhq7c99kA== X-Received: by 2002:aca:3687:: with SMTP id d129mr9836880oia.51.1552926289154; Mon, 18 Mar 2019 09:24:49 -0700 (PDT) From: Michael Roth To: qemu-devel@nongnu.org Date: Mon, 18 Mar 2019 11:24:08 -0500 Message-Id: <20190318162410.10183-6-mdroth@linux.vnet.ibm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190318162410.10183-1-mdroth@linux.vnet.ibm.com> References: <20190318162410.10183-1-mdroth@linux.vnet.ibm.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::22b Subject: [Qemu-devel] [PULL for-4.0 5/7] 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: peter.maydell@linaro.org, Matt Hines 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 *fix up some checkpatch warnings *fix domain reporting and add some sanity checks for debug Signed-off-by: Michael Roth --- configure | 2 +- qga/commands-win32.c | 317 ++++++++++++++++++++++++++++--------------- 2 files changed, 211 insertions(+), 108 deletions(-) diff --git a/configure b/configure index 7071f52584..02ea221272 100755 --- a/configure +++ b/configure @@ -4934,7 +4934,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 fb48463885..d40d61f605 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #endif #include @@ -485,56 +486,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) { @@ -544,90 +518,220 @@ 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, ui_slot, type; + int func, slot; + + /* + * 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/f= f543095(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)&ui_slot, size, NULL)) { + debug_error("failed to get PCI slot"); + ui_slot =3D -1; + partial_pci =3D true; + } + + /* + * SetupApi gives us the same information as driver with + * IoGetDeviceProperty. According to Microsoft: + * + * FunctionNumber =3D (USHORT)((propertyAddress) & 0x0000FFF= F) + * DeviceNumber =3D (USHORT)(((propertyAddress) >> 16) & 0x0= 000FFFF) + * SPDRP_ADDRESS is propertyAddress, so we do the same. + * + * https://docs.microsoft.com/en-us/windows/desktop/api/setupa= pi/nf-setupapi-setupdigetdeviceregistrypropertya + */ + 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; + slot =3D ((int)addr =3D=3D -1) ? -1 : (addr >> 16) & 0x000= 0FFFF; + if ((int)ui_slot !=3D slot) { + g_debug("mismatch with reported slot values: %d vs %d", + (int)ui_slot, slot); + } + pci->domain =3D 0; + pci->slot =3D (int)ui_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 @@ -685,7 +789,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; @@ -714,7 +819,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; @@ -728,7 +833,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; @@ -776,12 +881,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( @@ -797,7 +900,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)); @@ -831,9 +934,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.17.1