From patchwork Wed Apr 29 03:04:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Grzegorz Uriasz X-Patchwork-Id: 11515929 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B70021392 for ; Wed, 29 Apr 2020 03:06:17 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 93FB820731 for ; Wed, 29 Apr 2020 03:06:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="B5oRsmOx" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 93FB820731 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1jTd1g-0002uW-4P; Wed, 29 Apr 2020 03:04:44 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1jTd1e-0002uP-6v for xen-devel@lists.xenproject.org; Wed, 29 Apr 2020 03:04:42 +0000 X-Inumbo-ID: 2a06e332-89c6-11ea-ae69-bc764e2007e4 Received: from mail-wr1-x443.google.com (unknown [2a00:1450:4864:20::443]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 2a06e332-89c6-11ea-ae69-bc764e2007e4; Wed, 29 Apr 2020 03:04:39 +0000 (UTC) Received: by mail-wr1-x443.google.com with SMTP id x18so706488wrq.2 for ; Tue, 28 Apr 2020 20:04:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qRzsulywIjE+sQcPoBEKngALHTHNWGcwn3UAFri5+Is=; b=B5oRsmOxxtULX0ELvlErFeZeY0jak0zTDw+T63dGQmt8YuEujgUo5u+ir5d7gG3q7b Hvri0SdTK51dwZCcRpky83W1etxumYRvsNFey41OECwRVZLsKA4Vh1iGEqcirnik+pS/ szJVElSA3+3/MF+CVST65JqGVCfNJFJ13WZ78y/8v5YsiPP4jXZgKTGpFSV1Wm8dgxDo IDC+89MFvelQhTdaOtZVVm9HMmQXBv1ODxhFOQG0+xAoA1cNHLVByWacU6QBzgFMf+e4 3FL9wXYnFlyWytZpMjh1IPXLcwyJk1D5ZiE2/nQjpoqCX5dUZG0s4VBCkquww1F21hae mw4g== 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:mime-version:content-transfer-encoding; bh=qRzsulywIjE+sQcPoBEKngALHTHNWGcwn3UAFri5+Is=; b=RyatFJUCb5sZiGNYP57Vmfyr53LAcmtS/GWYWDz8Q1BPFqgrAgbrSxek14FMnN3LSZ ZSzWAP8VhI4+vEDAZoKCQpvmDuDrwf/Bo1vgzUqTJo4926wkaGLQSz7z9ETj/1YygnQU UTIwp+Pgda3vVn8ap36jLo+ubBX2/lE60e0L+6aR+iwiwZvDDgoOA5D7RxvOvpf2F1WB /gnE561hGe/DSSlx0DianrTvaD/ZmjGY9NYJXr3GRNJq4uOHee8DHYQ+dzeBBZjDmWMB Gtr8Q6rdy4guoNkmaQ0CxLXiNwt1KYJZyYoqa8dBswUTTMf8HAZ3kS4ByRHSFxR8xWTv c1aQ== X-Gm-Message-State: AGi0PubSgAjzQtIzjnXzjGmln5ceUkrNbGSu8/Q5WIdTb4cCcL6pUYYj 1NSJJCsyME/EbYCWvPd/1G8= X-Google-Smtp-Source: APiQypKtASVRZtrLSNfnMWkMLsFzDJUoGhbpBBFcLg/HpdRqjRqKpuxw46KWnaiyvF30jck0ZguBLw== X-Received: by 2002:adf:fc4f:: with SMTP id e15mr36701072wrs.415.1588129478643; Tue, 28 Apr 2020 20:04:38 -0700 (PDT) Received: from localhost.localdomain (public-gprs636909.centertel.pl. [5.184.31.46]) by smtp.gmail.com with ESMTPSA id o6sm19713725wrw.63.2020.04.28.20.04.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Apr 2020 20:04:38 -0700 (PDT) From: Grzegorz Uriasz To: qemu-devel@nongnu.org Subject: [PATCH v2 1/2] Fix undefined behaviour Date: Wed, 29 Apr 2020 03:04:08 +0000 Message-Id: <20200429030409.9406-2-gorbak25@gmail.com> X-Mailer: git-send-email 2.26.1 In-Reply-To: <20200429030409.9406-1-gorbak25@gmail.com> References: <20200429030409.9406-1-gorbak25@gmail.com> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: artur@puzio.waw.pl, Stefano Stabellini , Paul Durrant , jakub@bartmin.ski, marmarek@invisiblethingslab.com, Grzegorz Uriasz , Anthony Perard , j.nowak26@student.uw.edu.pl, xen-devel@lists.xenproject.org Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" This patch fixes qemu crashes when passing through an IGD device to HVM guests under XEN. The problem is that on almost every laptop reading the IGD ROM from SYSFS will fail, the reason for it is that the IGD rom is polymorphic and it modifies itself during bootup - this results in an invalid rom image - the kernel checks whether the image is valid and when that's not the case it won't allow userspace to read it. It seems that when the code was first written(xen_pt_load_rom.c) the kernel's back then didn't check whether the rom is valid and just passed the contents to userspace - because of this qemu also tries to repair the rom later in the code. When stating the rom the kernel isn't validating the rom contents so it is returning the proper size of the rom(32 4kb pages). This results in undefined behaviour - pci_assign_dev_load_option_rom is creating a buffer and then writes the size of the buffer to a pointer. In pci_assign_dev_load_option_rom under old kernels if the fstat would succeed then fread would also succeed - this means if the buffer is allocated the size of the buffer will be set. On newer kernels this is not the case - on all laptops I've tested(spanning a few generations of IGD) the fstat is successful and the buffer is allocated but the fread is failing - as the buffer is not deallocated the function is returning a valid pointer without setting the size of the buffer for the caller. The caller of pci_assign_dev_load_option_rom is holding the size of the buffer in an uninitialized variable and is just checking whether pci_assign_dev_load_option_rom returned a valid pointer. This later results in cpu_physical_memory_write(0xc0000, result_of_pci_assign_dev_load_option_rom, unitialized_variable) which depending on the compiler parameters, configure flags, etc... might crash qemu or might work - the xen 4.12 stable release with default configure parameters works but changing the compiler options slightly(for instance by enabling qemu debug) results in qemu crashing ¯\_(;-;)_/¯ The only situation when the original pci_assign_dev_load_option_rom works is when the IDG is not the boot gpu - this won't happen on any laptop and will be rare on desktops. This patch deallocates the buffer and returns NULL if reading the VBIOS fails - the caller of the function then properly shuts down qemu. The next patch in the series introduces a better method for getting the vbios so qemu does not exit when pci_assign_dev_load_option_rom fails - this is the reason I've changed error_report to warn_report as whether a failure in pci_assign_dev_load_option_rom is fatal depends on the caller. Signed-off-by: Grzegorz Uriasz Reviewed-by: Paul Durrant --- hw/xen/xen_pt_load_rom.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/xen/xen_pt_load_rom.c b/hw/xen/xen_pt_load_rom.c index a50a80837e..9f100dc159 100644 --- a/hw/xen/xen_pt_load_rom.c +++ b/hw/xen/xen_pt_load_rom.c @@ -38,12 +38,12 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev, fp = fopen(rom_file, "r+"); if (fp == NULL) { if (errno != ENOENT) { - error_report("pci-assign: Cannot open %s: %s", rom_file, strerror(errno)); + warn_report("pci-assign: Cannot open %s: %s", rom_file, strerror(errno)); } return NULL; } if (fstat(fileno(fp), &st) == -1) { - error_report("pci-assign: Cannot stat %s: %s", rom_file, strerror(errno)); + warn_report("pci-assign: Cannot stat %s: %s", rom_file, strerror(errno)); goto close_rom; } @@ -59,10 +59,9 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev, memset(ptr, 0xff, st.st_size); if (!fread(ptr, 1, st.st_size, fp)) { - error_report("pci-assign: Cannot read from host %s", rom_file); - error_printf("Device option ROM contents are probably invalid " - "(check dmesg).\nSkip option ROM probe with rombar=0, " - "or load from file with romfile=\n"); + warn_report("pci-assign: Cannot read from host %s", rom_file); + memory_region_unref(&dev->rom); + ptr = NULL; goto close_rom; } From patchwork Wed Apr 29 03:04:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Grzegorz Uriasz X-Patchwork-Id: 11515927 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DB1F81392 for ; Wed, 29 Apr 2020 03:06:14 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B6DFE20731 for ; Wed, 29 Apr 2020 03:06:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Ml9H7kdF" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B6DFE20731 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1jTd1k-0002vA-Cz; Wed, 29 Apr 2020 03:04:48 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1jTd1j-0002um-6S for xen-devel@lists.xenproject.org; Wed, 29 Apr 2020 03:04:47 +0000 X-Inumbo-ID: 2b74c630-89c6-11ea-9887-bc764e2007e4 Received: from mail-wm1-x342.google.com (unknown [2a00:1450:4864:20::342]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 2b74c630-89c6-11ea-9887-bc764e2007e4; Wed, 29 Apr 2020 03:04:41 +0000 (UTC) Received: by mail-wm1-x342.google.com with SMTP id e26so293207wmk.5 for ; Tue, 28 Apr 2020 20:04:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=MFxxzEsM5GfOkfgyaKw8Kz24FnJBi9lLjF7uh1T3+yM=; b=Ml9H7kdFfKHLrPPnYLICG9djXTuB/GA+1a6LqrTQxGGNkNJxCNdRS2clqs+BPiSaDo SyDSYfAFPEVvMLZE53vt6LjJUGrWhyg2uP48+5Sp8JH/PFYvzj47b4hIdShvxZBnCvzt d/MHprmO+6eDewWi8n5QAuvcyvODR4vbkp3lFjbCmAr5WpDkeuyk8frileoa4IteY9nl 63aJmdKg+mGax5YgJy6sQ5P8fsduxB/TCCu0sSM5W6EAyEP9+wr5mzYCYLTrFRWlaPgN vegKSMP7+zwJX5Dsx86WJlzPqx2lM0Ue6tru7DS1zb1UpztfuArjUPSTwPkXfGEVRaoA Jfnw== 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:mime-version:content-transfer-encoding; bh=MFxxzEsM5GfOkfgyaKw8Kz24FnJBi9lLjF7uh1T3+yM=; b=eWQZPnPjNYQYJ0zbukeSqBCGUpVm3h6A4jt18vBFzuxD9glKCTLewuYghvOIJiMoLv 5q47DUXIFFWbtM7QfCrq3NuzleE06Aqgjz5Nu3I2oS3s2b6z1m/fr4Uz6lxhiwqQZ/Um IKylFjCiI19fBdlkUncdirOmUUcnqeOtFV/kIuBjL0YMooCHShPLfekbhM1DkKqmF2EF yJm6oGfMQxaxeaPMl6e/h03WsQQ+pQJkHcqbe0jnB8BX80eZVtJT5h8wEpcVc+JNi/+7 9ziDK9F7IIlji/dIrHd2Lm+pioHbzjkxaa+jlPfN8cEjV+9HNwB0jkLYAZOcnrIXCBRO 9z4A== X-Gm-Message-State: AGi0PuZcNTYqGpmL3Fw2HEdtWNm+rhIDsZJWYjnfi9CegnUtwf/nUw5u 2WFnZn1uvXKEya8Nhpd2h5I= X-Google-Smtp-Source: APiQypJ7i6XB4Z4DtGjW0thFBqIHvxddUzWj5q8KwPgw4tknkPlZoRrX8MoglxKZaemp9rCnP0Ki8A== X-Received: by 2002:a1c:cc1a:: with SMTP id h26mr525239wmb.127.1588129480910; Tue, 28 Apr 2020 20:04:40 -0700 (PDT) Received: from localhost.localdomain (public-gprs636909.centertel.pl. [5.184.31.46]) by smtp.gmail.com with ESMTPSA id o6sm19713725wrw.63.2020.04.28.20.04.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Apr 2020 20:04:40 -0700 (PDT) From: Grzegorz Uriasz To: qemu-devel@nongnu.org Subject: [PATCH v2 2/2] Improve legacy vbios handling Date: Wed, 29 Apr 2020 03:04:09 +0000 Message-Id: <20200429030409.9406-3-gorbak25@gmail.com> X-Mailer: git-send-email 2.26.1 In-Reply-To: <20200429030409.9406-1-gorbak25@gmail.com> References: <20200429030409.9406-1-gorbak25@gmail.com> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: artur@puzio.waw.pl, Stefano Stabellini , Paul Durrant , jakub@bartmin.ski, marmarek@invisiblethingslab.com, Grzegorz Uriasz , Anthony Perard , j.nowak26@student.uw.edu.pl, xen-devel@lists.xenproject.org Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" The current method of getting the vbios is broken - it just isn't working on any device I've tested - the reason for this is explained in the previous patch. The vbios is polymorphic and getting a proper unmodified copy is often not possible without reverse engineering the firmware. We don't need an unmodified copy for most purposes - an unmodified copy is only needed for initializing the bios framebuffer and providing the bios with a corrupted copy of the rom won't do any damage as the bios will just ignore the rom. After the i915 driver takes over the vbios is only needed for reading some metadata/configuration stuff etc... I've tested that not having any kind of vbios in the guest actually works fine but on older generations of IGD there are some slight hiccups. To maximize compatibility the best approach is to just copy the results of the vbios execution directly to the guest. It turns out the vbios is always present on an hardcoded memory range in a reserved memory range from real mode - all we need to do is to memcpy it into the guest. The following patch does 2 things: 1) When pci_assign_dev_load_option_rom fails to read the vbios from sysfs(this works only when the igd is not the boot gpu - this is unlikely to happen) it falls back to using /dev/mem to copy the vbios directly to the guest. Using /dev/mem should be fine as there is more xen specific pci code which also relies on /dev/mem. 2) When dealing with IGD in the more generic code we skip the allocation of the rom resource - the reason for this is to prevent a malicious guest from modifying the vbios in the host -> this is needed as someone might try to pwn the i915 driver in the host by doing so (attach igd to guest, guest modifies vbios, the guest is terminated and the idg is reattached to the host, i915 driver in the host uses data from the modified vbios). This is also needed to not overwrite the proper shadow copy made before. I've tested this patch and it works fine - the guest isn't complaining about the missing vbios tables and the pci config space in the guest looks fine. Signed-off-by: Grzegorz Uriasz --- hw/xen/xen_pt.c | 8 +++++-- hw/xen/xen_pt_graphics.c | 48 +++++++++++++++++++++++++++++++++++++--- hw/xen/xen_pt_load_rom.c | 2 +- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index b91082cb8b..ffc3559dd4 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -483,8 +483,12 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd) i, r->size, r->base_addr, type); } - /* Register expansion ROM address */ - if (d->rom.base_addr && d->rom.size) { + /* + * Register expansion ROM address. If we are dealing with a ROM + * shadow copy for legacy vga devices then don't bother to map it + * as previous code creates a proper shadow copy + */ + if (d->rom.base_addr && d->rom.size && !(is_igd_vga_passthrough(d))) { uint32_t bar_data = 0; /* Re-set BAR reported by OS, otherwise ROM can't be read. */ diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index a3bc7e3921..fe0ef2685c 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -129,7 +129,7 @@ int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev) return 0; } -static void *get_vgabios(XenPCIPassthroughState *s, int *size, +static void *get_sysfs_vgabios(XenPCIPassthroughState *s, int *size, XenHostPCIDevice *dev) { return pci_assign_dev_load_option_rom(&s->dev, size, @@ -137,6 +137,45 @@ static void *get_vgabios(XenPCIPassthroughState *s, int *size, dev->dev, dev->func); } +static void xen_pt_direct_vbios_copy(XenPCIPassthroughState *s, Error **errp) +{ + int fd = -1; + void *guest_bios = NULL; + void *host_vbios = NULL; + /* This is always 32 pages in the real mode reserved region */ + int bios_size = 32 << XC_PAGE_SHIFT; + int vbios_addr = 0xc0000; + + fd = open("/dev/mem", O_RDONLY); + if (fd == -1) { + error_setg(errp, "Can't open /dev/mem: %s", strerror(errno)); + return; + } + host_vbios = mmap(NULL, bios_size, + PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, fd, vbios_addr); + close(fd); + + if (host_vbios == MAP_FAILED) { + error_setg(errp, "Failed to mmap host vbios: %s", strerror(errno)); + return; + } + + memory_region_init_ram(&s->dev.rom, OBJECT(&s->dev), + "legacy_vbios.rom", bios_size, &error_abort); + guest_bios = memory_region_get_ram_ptr(&s->dev.rom); + memcpy(guest_bios, host_vbios, bios_size); + + if (munmap(host_vbios, bios_size) == -1) { + XEN_PT_LOG(&s->dev, "Failed to unmap host vbios: %s\n", strerror(errno)); + } + + cpu_physical_memory_write(vbios_addr, guest_bios, bios_size); + memory_region_set_address(&s->dev.rom, vbios_addr); + pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->dev.rom); + s->dev.has_rom = true; + XEN_PT_LOG(&s->dev, "Legacy VBIOS registered\n"); +} + /* Refer to Seabios. */ struct rom_header { uint16_t signature; @@ -179,9 +218,11 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev, return; } - bios = get_vgabios(s, &bios_size, dev); + bios = get_sysfs_vgabios(s, &bios_size, dev); if (!bios) { - error_setg(errp, "VGA: Can't get VBIOS"); + XEN_PT_LOG(&s->dev, "Unable to get host VBIOS from sysfs - " + "falling back to a direct copy of memory ranges\n"); + xen_pt_direct_vbios_copy(s, errp); return; } @@ -223,6 +264,7 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev, /* Currently we fixed this address as a primary for legacy BIOS. */ cpu_physical_memory_write(0xc0000, bios, bios_size); + XEN_PT_LOG(&s->dev, "Legacy VBIOS registered\n"); } uint32_t igd_read_opregion(XenPCIPassthroughState *s) diff --git a/hw/xen/xen_pt_load_rom.c b/hw/xen/xen_pt_load_rom.c index 9f100dc159..8cd9aa84dc 100644 --- a/hw/xen/xen_pt_load_rom.c +++ b/hw/xen/xen_pt_load_rom.c @@ -65,7 +65,7 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev, goto close_rom; } - pci_register_bar(dev, PCI_ROM_SLOT, 0, &dev->rom); + pci_register_bar(dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_SPACE_MEMORY, &dev->rom); dev->has_rom = true; *size = st.st_size; close_rom: