@samitouri / QOSamiQemu / commits / 2d709a70c7

s390x/pci: Tighten region detection for BAR read/write

For PCISTG/PCISTB/PCILG instruction emulation, ensure that the offset and length provided by the guest does not overflow, and only return a memory region when the specified offset+length combination matches an existing subregion or the parent region. Cc: qemu-stable@nongnu.org Fixes: 4f6482bfe3 ("s390x/pci: search for subregion inside the BARs") Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com> Reviewed-by: Farhan Ali <alifm@linux.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com> Message-ID: <20260707070728.147203-3-borntraeger@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>

Matthew Rosato committed Jul 7, 2026 at 09:07 UTC 2d709a70c75724e972126671b2e2c0fca0b6e239
1 file changed +23 -1
hw/s390x/s390-pci-inst.c
+23 -1
@@ -392,13 +392,22 @@ static int zpci_endian_swap(uint64_t *ptr, uint8_t len)
392 static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset,
393 uint8_t len)
394 {
395 + uint64_t last = offset + len;
396 MemoryRegion *subregion;
397 uint64_t subregion_size;
398
399 + /*
400 + * Ensure the region is valid, the calculated address cannot wrap and that
401 + * it falls within this region.
402 + */
403 + if (!mr || offset > last || last > memory_region_size(mr)) {
404 + return NULL;
405 + }
406 +
407 QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
408 subregion_size = memory_region_size(subregion);
409 if ((offset >= subregion->addr) &&
401 - (offset + len) <= (subregion->addr + subregion_size)) {
410 + (last) <= (subregion->addr + subregion_size)) {
411 mr = subregion;
412 break;
413 }
@@ -413,6 +422,10 @@ static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
422
423 mr = pbdev->pdev->io_regions[pcias].memory;
424 mr = s390_get_subregion(mr, offset, len);
425 + if (!mr) {
426 + return MEMTX_ERROR;
427 + }
428 +
429 offset -= mr->addr;
430 return memory_region_dispatch_read(mr, offset, data,
431 size_memop(len) | MO_BE,
@@ -513,6 +526,10 @@ static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
526
527 mr = pbdev->pdev->io_regions[pcias].memory;
528 mr = s390_get_subregion(mr, offset, len);
529 + if (!mr) {
530 + return MEMTX_ERROR;
531 + }
532 +
533 offset -= mr->addr;
534 return memory_region_dispatch_write(mr, offset, data,
535 size_memop(len) | MO_BE,
@@ -900,6 +917,11 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
917
918 mr = pbdev->pdev->io_regions[pcias].memory;
919 mr = s390_get_subregion(mr, offset, len);
920 + if (!mr) {
921 + s390_program_interrupt(env, PGM_OPERAND, ra);
922 + return 0;
923 + }
924 +
925 offset -= mr->addr;
926
927 for (i = 0; i < len; i += 8) {