qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices
@ 2025-09-18 11:42 Peter Maydell
  2025-09-18 11:42 ` [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init Peter Maydell
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Peter Maydell @ 2025-09-18 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Richard Henderson, Helge Deller

This patchset fixes use-after-free bugs which show up if you put
some of the hppa pci-host devices through an "init -> deinit" lifecycle,
as the device-introspect-test does.

The problem in both cases is that we were calling pci_register_root_bus()
in instance_init: we should only call this in realize, as all the
other callers do.

These bugs show up if you run 'make check' with an ASAN enabled
build; they are also likely behind the intermittent segfaults
on s390 that RTH has noticed recently.

thanks
-- PMM

Peter Maydell (2):
  hw/pci-host/dino: Don't call pci_register_root_bus() in init
  hw/pci-host/astro: Don't call pci_regsiter_root_bus() in init

 hw/pci-host/astro.c | 27 +++++++-------
 hw/pci-host/dino.c  | 90 +++++++++++++++++++++------------------------
 2 files changed, 55 insertions(+), 62 deletions(-)

-- 
2.43.0



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init
  2025-09-18 11:42 [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Peter Maydell
@ 2025-09-18 11:42 ` Peter Maydell
  2025-09-22  9:18   ` Alex Bennée
  2025-09-18 11:42 ` [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() " Peter Maydell
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2025-09-18 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Richard Henderson, Helge Deller

In the dino PCI host bridge device, we call pci_register_root_bus()
in the device's instance_init. This is a problem for two reasons
 * the PCI bridge is then available to the rest of the simulation
   (e.g. via pci_qdev_find_device()), even though it hasn't
   yet been realized
 * we do not attempt to unregister in an instance_deinit,
   which means that if you go through an instance_init -> deinit
   lifecycle the freed memory for the host-bridge device is
   left on the pci_host_bridges list

ASAN reports the resulting use-after-free:

==1771223==ERROR: AddressSanitizer: heap-use-after-free on address 0x527000018f80 at pc 0x5b4b9d3369b5 bp 0x7ffd01929980 sp 0x7ffd01929978
WRITE of size 8 at 0x527000018f80 thread T0
    #0 0x5b4b9d3369b4 in pci_host_bus_register /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:608:5
    #1 0x5b4b9d321566 in pci_root_bus_internal_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:677:5
    #2 0x5b4b9d3215e0 in pci_root_bus_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:706:5
    #3 0x5b4b9d321fe5 in pci_register_root_bus /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:751:11
    #4 0x5b4b9d390521 in dino_pcihost_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci-host/dino.c:473:16

0x527000018f80 is located 1664 bytes inside of 12384-byte region [0x527000018900,0x52700001b960)
freed by thread T0 here:
    #0 0x5b4b9cab185a in free (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17ad85a) (BuildId: ca496bb2e4fc750ebd289b448bad8d99c0ecd140)
    #1 0x5b4b9e3ee723 in object_finalize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:734:9
    #2 0x5b4b9e3e69db in object_unref /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:1232:9
    #3 0x5b4b9ea6173c in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:237:5
    #4 0x5b4b9ec4e0f3 in qmp_marshal_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qapi/qapi-commands-qdev.c:65:14

previously allocated by thread T0 here:
    #0 0x5b4b9cab1af3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17adaf3) (BuildId: ca496bb2e4fc750ebd289b448bad8d99c0ecd140)
    #1 0x799d8270eb09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x5b4b9e3e75fc in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:767:15
    #3 0x5b4b9e3e7409 in object_new_with_class /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:782:12
    #4 0x5b4b9ea609a5 in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:206:11

where we allocated one instance of the dino device, put it on the
list, freed it, and then trying to allocate a second instance touches
the freed memory on the pci_host_bridges list.

Fix this by deferring all the setup of memory regions and registering
the PCI bridge to the device's realize method.  This brings it into
line with almost all other PCI host bridges, which call
pci_register_root_bus() in realize.

Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3118
Fixes: 63901b6cc4d8b4 ("dino: move PCI bus initialisation to dino_pcihost_init()")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/pci-host/dino.c | 90 +++++++++++++++++++++-------------------------
 1 file changed, 41 insertions(+), 49 deletions(-)

diff --git a/hw/pci-host/dino.c b/hw/pci-host/dino.c
index 11b353be2ea..924053499c1 100644
--- a/hw/pci-host/dino.c
+++ b/hw/pci-host/dino.c
@@ -413,6 +413,47 @@ static void dino_pcihost_reset(DeviceState *dev)
 static void dino_pcihost_realize(DeviceState *dev, Error **errp)
 {
     DinoState *s = DINO_PCI_HOST_BRIDGE(dev);
+    PCIHostState *phb = PCI_HOST_BRIDGE(dev);
+
+    /* Dino PCI access from main memory.  */
+    memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,
+                          s, "dino", 4096);
+
+    /* Dino PCI config. */
+    memory_region_init_io(&phb->conf_mem, OBJECT(phb),
+                          &dino_config_addr_ops, DEVICE(s),
+                          "pci-conf-idx", 4);
+    memory_region_init_io(&phb->data_mem, OBJECT(phb),
+                          &dino_config_data_ops, DEVICE(s),
+                          "pci-conf-data", 4);
+    memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR,
+                                &phb->conf_mem);
+    memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA,
+                                &phb->data_mem);
+
+    /* Dino PCI bus memory.  */
+    memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB);
+
+    phb->bus = pci_register_root_bus(DEVICE(s), "pci",
+                                     dino_set_irq, dino_pci_map_irq, s,
+                                     &s->pci_mem, get_system_io(),
+                                     PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS);
+
+    /* Set up windows into PCI bus memory.  */
+    for (int i = 1; i < 31; i++) {
+        uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
+        char *name = g_strdup_printf("PCI Outbound Window %d", i);
+        memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s),
+                                 name, &s->pci_mem, addr,
+                                 DINO_MEM_CHUNK_SIZE);
+        g_free(name);
+    }
+
+    pci_setup_iommu(phb->bus, &dino_iommu_ops, s);
+
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->this_mem);
+
+    qdev_init_gpio_in(dev, dino_set_irq, DINO_IRQS);
 
     /* Set up PCI view of memory: Bus master address space.  */
     memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB);
@@ -444,54 +485,6 @@ static void dino_pcihost_unrealize(DeviceState *dev)
     address_space_destroy(&s->bm_as);
 }
 
-static void dino_pcihost_init(Object *obj)
-{
-    DinoState *s = DINO_PCI_HOST_BRIDGE(obj);
-    PCIHostState *phb = PCI_HOST_BRIDGE(obj);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-    int i;
-
-    /* Dino PCI access from main memory.  */
-    memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,
-                          s, "dino", 4096);
-
-    /* Dino PCI config. */
-    memory_region_init_io(&phb->conf_mem, OBJECT(phb),
-                          &dino_config_addr_ops, DEVICE(s),
-                          "pci-conf-idx", 4);
-    memory_region_init_io(&phb->data_mem, OBJECT(phb),
-                          &dino_config_data_ops, DEVICE(s),
-                          "pci-conf-data", 4);
-    memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR,
-                                &phb->conf_mem);
-    memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA,
-                                &phb->data_mem);
-
-    /* Dino PCI bus memory.  */
-    memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB);
-
-    phb->bus = pci_register_root_bus(DEVICE(s), "pci",
-                                     dino_set_irq, dino_pci_map_irq, s,
-                                     &s->pci_mem, get_system_io(),
-                                     PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS);
-
-    /* Set up windows into PCI bus memory.  */
-    for (i = 1; i < 31; i++) {
-        uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
-        char *name = g_strdup_printf("PCI Outbound Window %d", i);
-        memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s),
-                                 name, &s->pci_mem, addr,
-                                 DINO_MEM_CHUNK_SIZE);
-        g_free(name);
-    }
-
-    pci_setup_iommu(phb->bus, &dino_iommu_ops, s);
-
-    sysbus_init_mmio(sbd, &s->this_mem);
-
-    qdev_init_gpio_in(DEVICE(obj), dino_set_irq, DINO_IRQS);
-}
-
 static const Property dino_pcihost_properties[] = {
     DEFINE_PROP_LINK("memory-as", DinoState, memory_as, TYPE_MEMORY_REGION,
                      MemoryRegion *),
@@ -511,7 +504,6 @@ static void dino_pcihost_class_init(ObjectClass *klass, const void *data)
 static const TypeInfo dino_pcihost_info = {
     .name          = TYPE_DINO_PCI_HOST_BRIDGE,
     .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_init = dino_pcihost_init,
     .instance_size = sizeof(DinoState),
     .class_init    = dino_pcihost_class_init,
 };
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() in init
  2025-09-18 11:42 [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Peter Maydell
  2025-09-18 11:42 ` [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init Peter Maydell
@ 2025-09-18 11:42 ` Peter Maydell
  2025-09-18 11:59   ` Peter Maydell
  2025-09-22  9:18   ` Alex Bennée
  2025-09-22  9:03 ` [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Alex Bennée
  2025-09-23 23:53 ` Richard Henderson
  3 siblings, 2 replies; 8+ messages in thread
From: Peter Maydell @ 2025-09-18 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Richard Henderson, Helge Deller

In the astro PCI host bridge device, we call pci_register_root_bus()
in the device's instance_init. This is a problem for two reasons
 * the PCI bridge is then available to the rest of the simulation
   (e.g. via pci_qdev_find_device()), even though it hasn't
   yet been realized
 * we do not attempt to unregister in an instance_deinit,
   which means that if you go through an instance_init -> deinit
   lifecycle the freed memory for the host-bridge device is
   left on the pci_host_bridges list

ASAN reports the resulting use-after-free:

==1776584==ERROR: AddressSanitizer: heap-use-after-free on address 0x51f00000cb00 at pc 0x5b2d460a89b5 bp 0x7ffef7617f50 sp 0x7ffef7617f48
WRITE of size 8 at 0x51f00000cb00 thread T0
    #0 0x5b2d460a89b4 in pci_host_bus_register /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:608:5
    #1 0x5b2d46093566 in pci_root_bus_internal_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:677:5
    #2 0x5b2d460935e0 in pci_root_bus_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:706:5
    #3 0x5b2d46093fe5 in pci_register_root_bus /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:751:11
    #4 0x5b2d46fe2335 in elroy_pcihost_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci-host/astro.c:455:16

0x51f00000cb00 is located 1664 bytes inside of 3456-byte region [0x51f00000c480,0x51f00000d200)
freed by thread T0 here:
    #0 0x5b2d4582385a in free (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17ad85a) (BuildId: 692b49eedc6fb0ef618bbb6784a09311b3b7f1e8)
    #1 0x5b2d47160723 in object_finalize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:734:9
    #2 0x5b2d471589db in object_unref /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:1232:9
    #3 0x5b2d477d373c in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:237:5

previously allocated by thread T0 here:
    #0 0x5b2d45823af3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17adaf3) (BuildId: 692b49eedc6fb0ef618bbb6784a09311b3b7f1e8)
    #1 0x79728fa08b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x5b2d471595fc in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:767:15
    #3 0x5b2d47159409 in object_new_with_class /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:782:12
    #4 0x5b2d477d29a5 in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:206:11

Cc: qemu-stable@nongnu.org
Fixes: e029bb00a79be ("hw/pci-host: Add Astro system bus adapter found on PA-RISC machines")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3118
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/pci-host/astro.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index 859e308c577..1024ede7b68 100644
--- a/hw/pci-host/astro.c
+++ b/hw/pci-host/astro.c
@@ -424,22 +424,23 @@ static void elroy_reset(DeviceState *dev)
     }
 }
 
-static void elroy_pcihost_init(Object *obj)
+static void elroy_pcihost_realize(DeviceState *dev, Error **errp)
 {
-    ElroyState *s = ELROY_PCI_HOST_BRIDGE(obj);
-    PCIHostState *phb = PCI_HOST_BRIDGE(obj);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    ElroyState *s = ELROY_PCI_HOST_BRIDGE(dev);
+    PCIHostState *phb = PCI_HOST_BRIDGE(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    Object *obj = OBJECT(s);
 
     /* Elroy config access from CPU.  */
-    memory_region_init_io(&s->this_mem, OBJECT(s), &elroy_chip_ops,
+    memory_region_init_io(&s->this_mem, obj, &elroy_chip_ops,
                           s, "elroy", 0x2000);
 
     /* Elroy PCI config. */
-    memory_region_init_io(&phb->conf_mem, OBJECT(phb),
-                          &elroy_config_addr_ops, DEVICE(s),
+    memory_region_init_io(&phb->conf_mem, obj,
+                          &elroy_config_addr_ops, dev,
                           "pci-conf-idx", 8);
-    memory_region_init_io(&phb->data_mem, OBJECT(phb),
-                          &elroy_config_data_ops, DEVICE(s),
+    memory_region_init_io(&phb->data_mem, obj,
+                          &elroy_config_data_ops, dev,
                           "pci-conf-data", 8);
     memory_region_add_subregion(&s->this_mem, 0x40,
                                 &phb->conf_mem);
@@ -447,8 +448,8 @@ static void elroy_pcihost_init(Object *obj)
                                 &phb->data_mem);
 
     /* Elroy PCI bus memory.  */
-    memory_region_init(&s->pci_mmio, OBJECT(s), "pci-mmio", UINT64_MAX);
-    memory_region_init_io(&s->pci_io, OBJECT(s), &unassigned_io_ops, obj,
+    memory_region_init(&s->pci_mmio, obj, "pci-mmio", UINT64_MAX);
+    memory_region_init_io(&s->pci_io, obj, &unassigned_io_ops, obj,
                             "pci-isa-mmio",
                             ((uint32_t) IOS_DIST_BASE_SIZE) / ROPES_PER_IOC);
 
@@ -459,7 +460,7 @@ static void elroy_pcihost_init(Object *obj)
 
     sysbus_init_mmio(sbd, &s->this_mem);
 
-    qdev_init_gpio_in(DEVICE(obj), elroy_set_irq, ELROY_IRQS);
+    qdev_init_gpio_in(dev, elroy_set_irq, ELROY_IRQS);
 }
 
 static const VMStateDescription vmstate_elroy = {
@@ -487,6 +488,7 @@ static void elroy_pcihost_class_init(ObjectClass *klass, const void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     device_class_set_legacy_reset(dc, elroy_reset);
+    dc->realize = elroy_pcihost_realize;
     dc->vmsd = &vmstate_elroy;
     dc->user_creatable = false;
 }
@@ -494,7 +496,6 @@ static void elroy_pcihost_class_init(ObjectClass *klass, const void *data)
 static const TypeInfo elroy_pcihost_info = {
     .name          = TYPE_ELROY_PCI_HOST_BRIDGE,
     .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_init = elroy_pcihost_init,
     .instance_size = sizeof(ElroyState),
     .class_init    = elroy_pcihost_class_init,
 };
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() in init
  2025-09-18 11:42 ` [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() " Peter Maydell
@ 2025-09-18 11:59   ` Peter Maydell
  2025-09-22  9:18   ` Alex Bennée
  1 sibling, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2025-09-18 11:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: Richard Henderson, Helge Deller

On Thu, 18 Sept 2025 at 12:43, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> In the astro PCI host bridge device, we call pci_register_root_bus()
> in the device's instance_init. This is a problem for two reasons

oops, typo in subject line: s/regsiter/register/

-- PMM


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices
  2025-09-18 11:42 [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Peter Maydell
  2025-09-18 11:42 ` [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init Peter Maydell
  2025-09-18 11:42 ` [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() " Peter Maydell
@ 2025-09-22  9:03 ` Alex Bennée
  2025-09-23 23:53 ` Richard Henderson
  3 siblings, 0 replies; 8+ messages in thread
From: Alex Bennée @ 2025-09-22  9:03 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, Richard Henderson, Helge Deller

Peter Maydell <peter.maydell@linaro.org> writes:

> This patchset fixes use-after-free bugs which show up if you put
> some of the hppa pci-host devices through an "init -> deinit" lifecycle,
> as the device-introspect-test does.
>
> The problem in both cases is that we were calling pci_register_root_bus()
> in instance_init: we should only call this in realize, as all the
> other callers do.
>
> These bugs show up if you run 'make check' with an ASAN enabled
> build; they are also likely behind the intermittent segfaults
> on s390 that RTH has noticed recently.

Tested-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init
  2025-09-18 11:42 ` [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init Peter Maydell
@ 2025-09-22  9:18   ` Alex Bennée
  0 siblings, 0 replies; 8+ messages in thread
From: Alex Bennée @ 2025-09-22  9:18 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, Richard Henderson, Helge Deller

Peter Maydell <peter.maydell@linaro.org> writes:

> In the dino PCI host bridge device, we call pci_register_root_bus()
> in the device's instance_init. This is a problem for two reasons
>  * the PCI bridge is then available to the rest of the simulation
>    (e.g. via pci_qdev_find_device()), even though it hasn't
>    yet been realized
>  * we do not attempt to unregister in an instance_deinit,
>    which means that if you go through an instance_init -> deinit
>    lifecycle the freed memory for the host-bridge device is
>    left on the pci_host_bridges list
>
> ASAN reports the resulting use-after-free:
>
> ==1771223==ERROR: AddressSanitizer: heap-use-after-free on address 0x527000018f80 at pc 0x5b4b9d3369b5 bp 0x7ffd01929980 sp 0x7ffd01929978
> WRITE of size 8 at 0x527000018f80 thread T0
>     #0 0x5b4b9d3369b4 in pci_host_bus_register /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:608:5
>     #1 0x5b4b9d321566 in pci_root_bus_internal_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:677:5
>     #2 0x5b4b9d3215e0 in pci_root_bus_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:706:5
>     #3 0x5b4b9d321fe5 in pci_register_root_bus /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:751:11
>     #4 0x5b4b9d390521 in dino_pcihost_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci-host/dino.c:473:16
>
> 0x527000018f80 is located 1664 bytes inside of 12384-byte region [0x527000018900,0x52700001b960)
> freed by thread T0 here:
>     #0 0x5b4b9cab185a in free (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17ad85a) (BuildId: ca496bb2e4fc750ebd289b448bad8d99c0ecd140)
>     #1 0x5b4b9e3ee723 in object_finalize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:734:9
>     #2 0x5b4b9e3e69db in object_unref /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:1232:9
>     #3 0x5b4b9ea6173c in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:237:5
>     #4 0x5b4b9ec4e0f3 in qmp_marshal_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qapi/qapi-commands-qdev.c:65:14
>
> previously allocated by thread T0 here:
>     #0 0x5b4b9cab1af3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17adaf3) (BuildId: ca496bb2e4fc750ebd289b448bad8d99c0ecd140)
>     #1 0x799d8270eb09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
>     #2 0x5b4b9e3e75fc in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:767:15
>     #3 0x5b4b9e3e7409 in object_new_with_class /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:782:12
>     #4 0x5b4b9ea609a5 in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:206:11
>
> where we allocated one instance of the dino device, put it on the
> list, freed it, and then trying to allocate a second instance touches
> the freed memory on the pci_host_bridges list.
>
> Fix this by deferring all the setup of memory regions and registering
> the PCI bridge to the device's realize method.  This brings it into
> line with almost all other PCI host bridges, which call
> pci_register_root_bus() in realize.

Would it be worth adding a kdoc comment to the declaration of
pci_register_root_bus to explain this?

>
> Cc: qemu-stable@nongnu.org
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3118
> Fixes: 63901b6cc4d8b4 ("dino: move PCI bus initialisation to dino_pcihost_init()")
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/pci-host/dino.c | 90 +++++++++++++++++++++-------------------------
>  1 file changed, 41 insertions(+), 49 deletions(-)
>
> diff --git a/hw/pci-host/dino.c b/hw/pci-host/dino.c
> index 11b353be2ea..924053499c1 100644
> --- a/hw/pci-host/dino.c
> +++ b/hw/pci-host/dino.c
> @@ -413,6 +413,47 @@ static void dino_pcihost_reset(DeviceState *dev)
>  static void dino_pcihost_realize(DeviceState *dev, Error **errp)
>  {
>      DinoState *s = DINO_PCI_HOST_BRIDGE(dev);
> +    PCIHostState *phb = PCI_HOST_BRIDGE(dev);
> +
> +    /* Dino PCI access from main memory.  */
> +    memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,
> +                          s, "dino", 4096);
> +
> +    /* Dino PCI config. */
> +    memory_region_init_io(&phb->conf_mem, OBJECT(phb),
> +                          &dino_config_addr_ops, DEVICE(s),
> +                          "pci-conf-idx", 4);
> +    memory_region_init_io(&phb->data_mem, OBJECT(phb),
> +                          &dino_config_data_ops, DEVICE(s),
> +                          "pci-conf-data", 4);
> +    memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR,
> +                                &phb->conf_mem);
> +    memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA,
> +                                &phb->data_mem);
> +
> +    /* Dino PCI bus memory.  */
> +    memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB);
> +
> +    phb->bus = pci_register_root_bus(DEVICE(s), "pci",
> +                                     dino_set_irq, dino_pci_map_irq, s,
> +                                     &s->pci_mem, get_system_io(),
> +                                     PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS);
> +
> +    /* Set up windows into PCI bus memory.  */
> +    for (int i = 1; i < 31; i++) {
> +        uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
> +        char *name = g_strdup_printf("PCI Outbound Window %d", i);
> +        memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s),
> +                                 name, &s->pci_mem, addr,
> +                                 DINO_MEM_CHUNK_SIZE);
> +        g_free(name);

minor nit: this could be an autofree but I get you are just moving code
here.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() in init
  2025-09-18 11:42 ` [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() " Peter Maydell
  2025-09-18 11:59   ` Peter Maydell
@ 2025-09-22  9:18   ` Alex Bennée
  1 sibling, 0 replies; 8+ messages in thread
From: Alex Bennée @ 2025-09-22  9:18 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, Richard Henderson, Helge Deller

Peter Maydell <peter.maydell@linaro.org> writes:

> In the astro PCI host bridge device, we call pci_register_root_bus()
> in the device's instance_init. This is a problem for two reasons
>  * the PCI bridge is then available to the rest of the simulation
>    (e.g. via pci_qdev_find_device()), even though it hasn't
>    yet been realized
>  * we do not attempt to unregister in an instance_deinit,
>    which means that if you go through an instance_init -> deinit
>    lifecycle the freed memory for the host-bridge device is
>    left on the pci_host_bridges list
>
> ASAN reports the resulting use-after-free:
>
> ==1776584==ERROR: AddressSanitizer: heap-use-after-free on address 0x51f00000cb00 at pc 0x5b2d460a89b5 bp 0x7ffef7617f50 sp 0x7ffef7617f48
> WRITE of size 8 at 0x51f00000cb00 thread T0
>     #0 0x5b2d460a89b4 in pci_host_bus_register /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:608:5
>     #1 0x5b2d46093566 in pci_root_bus_internal_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:677:5
>     #2 0x5b2d460935e0 in pci_root_bus_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:706:5
>     #3 0x5b2d46093fe5 in pci_register_root_bus /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci/pci.c:751:11
>     #4 0x5b2d46fe2335 in elroy_pcihost_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../hw/pci-host/astro.c:455:16
>
> 0x51f00000cb00 is located 1664 bytes inside of 3456-byte region [0x51f00000c480,0x51f00000d200)
> freed by thread T0 here:
>     #0 0x5b2d4582385a in free (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17ad85a) (BuildId: 692b49eedc6fb0ef618bbb6784a09311b3b7f1e8)
>     #1 0x5b2d47160723 in object_finalize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:734:9
>     #2 0x5b2d471589db in object_unref /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:1232:9
>     #3 0x5b2d477d373c in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:237:5
>
> previously allocated by thread T0 here:
>     #0 0x5b2d45823af3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/qemu-system-hppa+0x17adaf3) (BuildId: 692b49eedc6fb0ef618bbb6784a09311b3b7f1e8)
>     #1 0x79728fa08b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
>     #2 0x5b2d471595fc in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:767:15
>     #3 0x5b2d47159409 in object_new_with_class /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/object.c:782:12
>     #4 0x5b2d477d29a5 in qmp_device_list_properties /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/hppa-asan/../../qom/qom-qmp-cmds.c:206:11
>
> Cc: qemu-stable@nongnu.org
> Fixes: e029bb00a79be ("hw/pci-host: Add Astro system bus adapter found on PA-RISC machines")
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3118
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

with the typo fix:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices
  2025-09-18 11:42 [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Peter Maydell
                   ` (2 preceding siblings ...)
  2025-09-22  9:03 ` [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Alex Bennée
@ 2025-09-23 23:53 ` Richard Henderson
  3 siblings, 0 replies; 8+ messages in thread
From: Richard Henderson @ 2025-09-23 23:53 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel; +Cc: Helge Deller

On 9/18/25 04:42, Peter Maydell wrote:
> This patchset fixes use-after-free bugs which show up if you put
> some of the hppa pci-host devices through an "init -> deinit" lifecycle,
> as the device-introspect-test does.
> 
> The problem in both cases is that we were calling pci_register_root_bus()
> in instance_init: we should only call this in realize, as all the
> other callers do.
> 
> These bugs show up if you run 'make check' with an ASAN enabled
> build; they are also likely behind the intermittent segfaults
> on s390 that RTH has noticed recently.
> 
> thanks
> -- PMM
> 
> Peter Maydell (2):
>    hw/pci-host/dino: Don't call pci_register_root_bus() in init
>    hw/pci-host/astro: Don't call pci_regsiter_root_bus() in init
> 
>   hw/pci-host/astro.c | 27 +++++++-------
>   hw/pci-host/dino.c  | 90 +++++++++++++++++++++------------------------
>   2 files changed, 55 insertions(+), 62 deletions(-)
> 

Queued, thanks.

r~


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-09-23 23:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18 11:42 [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Peter Maydell
2025-09-18 11:42 ` [PATCH 1/2] hw/pci-host/dino: Don't call pci_register_root_bus() in init Peter Maydell
2025-09-22  9:18   ` Alex Bennée
2025-09-18 11:42 ` [PATCH 2/2] hw/pci-host/astro: Don't call pci_regsiter_root_bus() " Peter Maydell
2025-09-18 11:59   ` Peter Maydell
2025-09-22  9:18   ` Alex Bennée
2025-09-22  9:03 ` [PATCH 0/2] hw/pci-host: fix use-after-free in hppa pci-host devices Alex Bennée
2025-09-23 23:53 ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).