aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Mathieu-Daudé <f4bug@amsat.org>2020-07-17 17:17:05 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2020-11-03 09:42:53 -0500
commit4177b062fc58dd250667415e487618ac59393d04 (patch)
tree77bf6c1939e47d16e7171ee68cddc9266c983b7b
parentf8b8f3746327d577cdd25d6f86bd993178aece58 (diff)
downloadqemu-4177b062fc58dd250667415e487618ac59393d04.zip
qemu-4177b062fc58dd250667415e487618ac59393d04.tar.gz
qemu-4177b062fc58dd250667415e487618ac59393d04.tar.bz2
hw/isa/lpc_ich9: Ignore reserved/invalid SCI IRQ
libFuzzer triggered the following assertion: cat << EOF | qemu-system-i386 -M pc-q35-5.0 \ -nographic -monitor none -serial none \ -qtest stdio -d guest_errors -trace pci\* outl 0xcf8 0x8400f841 outl 0xcfc 0xebed205d outl 0x5d02 0xedf82049 EOF pci_cfg_write ICH9-LPC 31:0 @0x41 <- 0xebed205d hw/pci/pci.c:268: int pci_bus_get_irq_level(PCIBus *, int): Assertion `irq_num < bus->nirq' failed. This is because ich9_lpc_sci_irq() returns -1 for reserved (illegal) values, but ich9_lpc_pmbase_sci_update() considers it valid and store it in a 8-bit unsigned type. Then the 255 value is used as GSI IRQ, resulting in a PIRQ value of 247, more than ICH9_LPC_NB_PIRQS (8). Fix by simply ignoring the invalid access (and reporting it): pci_cfg_write ICH9-LPC 31:0 @0x41 <- 0xebed205d ICH9 LPC: SCI IRQ SEL #3 is reserved pci_cfg_read mch 00:0 @0x0 -> 0x8086 pci_cfg_read mch 00:0 @0x0 -> 0x29c08086 ... Cc: qemu-stable@nongnu.org Reported-by: Alexander Bulekov <alxndr@bu.edu> Fixes: 8f242cb724 ("ich9: implement SCI_IRQ_SEL register") BugLink: https://bugs.launchpad.net/qemu/+bug/1878642 Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-Id: <20200717151705.18611-1-f4bug@amsat.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--hw/isa/lpc_ich9.c14
-rw-r--r--include/hw/i386/ich9.h1
2 files changed, 12 insertions, 3 deletions
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 04e5323..087a18d 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -29,6 +29,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "qapi/visitor.h"
#include "qemu/range.h"
@@ -312,10 +313,12 @@ void ich9_generate_smi(void)
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
}
+/* Returns -1 on error, IRQ number on success */
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
{
- switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
- ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
+ uint8_t sel = lpc->d.config[ICH9_LPC_ACPI_CTRL] &
+ ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK;
+ switch (sel) {
case ICH9_LPC_ACPI_CTRL_9:
return 9;
case ICH9_LPC_ACPI_CTRL_10:
@@ -328,6 +331,8 @@ static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
return 21;
default:
/* reserved */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ICH9 LPC: SCI IRQ SEL #%u is reserved\n", sel);
break;
}
return -1;
@@ -459,7 +464,7 @@ ich9_lpc_pmbase_sci_update(ICH9LPCState *lpc)
{
uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
uint8_t acpi_cntl = pci_get_long(lpc->d.config + ICH9_LPC_ACPI_CTRL);
- uint8_t new_gsi;
+ int new_gsi;
if (acpi_cntl & ICH9_LPC_ACPI_CTRL_ACPI_EN) {
pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
@@ -470,6 +475,9 @@ ich9_lpc_pmbase_sci_update(ICH9LPCState *lpc)
ich9_pm_iospace_update(&lpc->pm, pm_io_base);
new_gsi = ich9_lpc_sci_irq(lpc);
+ if (new_gsi == -1) {
+ return;
+ }
if (lpc->sci_level && new_gsi != lpc->sci_gsi) {
qemu_set_irq(lpc->pm.irq, 0);
lpc->sci_gsi = new_gsi;
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 294024b..d1ea000 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -144,6 +144,7 @@ struct ICH9LPCState {
#define ICH9_LPC_PMBASE_BASE_ADDRESS_MASK Q35_MASK(32, 15, 7)
#define ICH9_LPC_PMBASE_RTE 0x1
#define ICH9_LPC_PMBASE_DEFAULT 0x1
+
#define ICH9_LPC_ACPI_CTRL 0x44
#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80
#define ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK Q35_MASK(8, 2, 0)