diff options
author | njl <njl@FreeBSD.org> | 2004-11-30 06:55:43 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2004-11-30 06:55:43 +0000 |
commit | 504bb0d4c899c5de8eb35b1d57ebd6411f1fed30 (patch) | |
tree | 4ae5e1faa4b4c4b3334e55b1e3f0c5e6fa942eca /sys/dev/acpica | |
parent | 7822d39332bec2bbf561a95f0cbc70fe67ca6a05 (diff) | |
download | FreeBSD-src-504bb0d4c899c5de8eb35b1d57ebd6411f1fed30.zip FreeBSD-src-504bb0d4c899c5de8eb35b1d57ebd6411f1fed30.tar.gz |
Make sure the link array is big enough to hold both _CRS and _PRS
resource lists. It used to be sized based only on _CRS, hence _PRS could
perform an out-of-bounds access if it was larger (i.e., when there are
dependent functions). Add asserts to detect this case. Note, this is
only a temporary fix and I believe _PRS and _CRS should have separate
arrays.
Also, fix a typo where the wrong irq was being check for the APIC case.
Submitted by: tegge
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r-- | sys/dev/acpica/acpi_pci_link.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/sys/dev/acpica/acpi_pci_link.c b/sys/dev/acpica/acpi_pci_link.c index c79cc04..e6675f1 100644 --- a/sys/dev/acpica/acpi_pci_link.c +++ b/sys/dev/acpica/acpi_pci_link.c @@ -131,12 +131,16 @@ acpi_pci_link_probe(device_t dev) } static ACPI_STATUS -acpi_count_resources(ACPI_RESOURCE *res, void *context) +acpi_count_irq_resources(ACPI_RESOURCE *res, void *context) { int *count; count = (int *)context; - (*count)++; + switch (res->Id) { + case ACPI_RSTYPE_IRQ: + case ACPI_RSTYPE_EXT_IRQ: + (*count)++; + } return (AE_OK); } @@ -148,11 +152,13 @@ link_add_crs(ACPI_RESOURCE *res, void *context) ACPI_SERIAL_ASSERT(pci_link); req = (struct link_res_request *)context; - link = &req->sc->pl_links[req->count]; - req->count++; switch (res->Id) { case ACPI_RSTYPE_IRQ: case ACPI_RSTYPE_EXT_IRQ: + KASSERT(req->count < req->sc->pl_num_links, + ("link_add_crs: array boundary violation")); + link = &req->sc->pl_links[req->count]; + req->count++; if (res->Id == ACPI_RSTYPE_IRQ) { if (res->Data.Irq.NumberOfInterrupts > 0) { KASSERT(res->Data.Irq.NumberOfInterrupts == 1, @@ -188,11 +194,13 @@ link_add_prs(ACPI_RESOURCE *res, void *context) ACPI_SERIAL_ASSERT(pci_link); req = (struct link_res_request *)context; - link = &req->sc->pl_links[req->count]; - req->count++; switch (res->Id) { case ACPI_RSTYPE_IRQ: case ACPI_RSTYPE_EXT_IRQ: + KASSERT(req->count < req->sc->pl_num_links, + ("link_add_prs: array boundary violation")); + link = &req->sc->pl_links[req->count]; + req->count++; /* * Stash a copy of the resource for later use when doing @@ -220,7 +228,7 @@ link_add_prs(ACPI_RESOURCE *res, void *context) M_PCI_LINK, M_WAITOK | M_ZERO); for (i = 0; i < link->l_num_irqs; i++) { link->l_irqs[i] = irqs[i]; - if (irqs[1] >= NUM_ISA_INTERRUPTS) + if (irqs[i] >= NUM_ISA_INTERRUPTS) link->l_isa_irq = 0; } break; @@ -283,6 +291,7 @@ acpi_pci_link_attach(device_t dev) struct link_res_request req; ACPI_STATUS status; int i; + int prslinks; sc = device_get_softc(dev); ACPI_SERIAL_BEGIN(pci_link); @@ -292,11 +301,24 @@ acpi_pci_link_attach(device_t dev) * a link array to allocate. */ status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", - acpi_count_resources, &sc->pl_num_links); + acpi_count_irq_resources, &sc->pl_num_links); if (ACPI_FAILURE(status)) return (ENXIO); if (sc->pl_num_links == 0) return (0); + + /* + * Try to make the number of resources sufficiently large + * for traversal of both _PRS and _CRS. + * + * XXX Temporary fix for out-of-bounds access in prs_add_links(). + * We really need to handle these in separate arrays. -- njl + */ + prslinks = 0; + status = AcpiWalkResources(acpi_get_handle(dev), "_PRS", + acpi_count_irq_resources, &prslinks); + if (prslinks > sc->pl_num_links) + sc->pl_num_links = prslinks; sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links, M_PCI_LINK, M_WAITOK | M_ZERO); |