From: Matthew Rosato <[email protected]> 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: [email protected] Fixes: 4f6482bfe3 ("s390x/pci: search for subregion inside the BARs") Signed-off-by: Matthew Rosato <[email protected]> Reviewed-by: Christian Borntraeger <[email protected]> Reviewed-by: Farhan Ali <[email protected]> Signed-off-by: Christian Borntraeger <[email protected]> Message-ID: <[email protected]> Signed-off-by: Cornelia Huck <[email protected]> (cherry picked from commit 2d709a70c75724e972126671b2e2c0fca0b6e239) Signed-off-by: Michael Tokarev <[email protected]> diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 6d95b96bef2..79a6a9c8524 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -390,13 +390,22 @@ static int zpci_endian_swap(uint64_t *ptr, uint8_t len) static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset, uint8_t len) { + uint64_t last = offset + len; MemoryRegion *subregion; uint64_t subregion_size; + /* + * Ensure the region is valid, the calculated address cannot wrap and that + * it falls within this region. + */ + if (!mr || offset > last || last > memory_region_size(mr)) { + return NULL; + } + QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { subregion_size = int128_get64(subregion->size); if ((offset >= subregion->addr) && - (offset + len) <= (subregion->addr + subregion_size)) { + (last) <= (subregion->addr + subregion_size)) { mr = subregion; break; } @@ -411,6 +420,10 @@ static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias, mr = pbdev->pdev->io_regions[pcias].memory; mr = s390_get_subregion(mr, offset, len); + if (!mr) { + return MEMTX_ERROR; + } + offset -= mr->addr; return memory_region_dispatch_read(mr, offset, data, size_memop(len) | MO_BE, @@ -511,6 +524,10 @@ static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias, mr = pbdev->pdev->io_regions[pcias].memory; mr = s390_get_subregion(mr, offset, len); + if (!mr) { + return MEMTX_ERROR; + } + offset -= mr->addr; return memory_region_dispatch_write(mr, offset, data, size_memop(len) | MO_BE, @@ -898,6 +915,11 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, mr = pbdev->pdev->io_regions[pcias].memory; mr = s390_get_subregion(mr, offset, len); + if (!mr) { + s390_program_interrupt(env, PGM_OPERAND, ra); + return 0; + } + offset -= mr->addr; for (i = 0; i < len; i += 8) { -- 2.47.3
