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) {