Sun Mar 8 11:03:19 2020 UTC ()
Pull up following revision(s) (requested by chs in ticket #765):

	sys/dev/acpi/acpi_pci_link.c: revision 1.25

apply FreeBSD revs r214848 and r214849:

    r214849 | jkim | 2010-11-05 13:24:26 -0700 (Fri, 05 Nov 2010) | 2 lines
    Add a forgotten change from the previous commit.
    r214848 | jkim | 2010-11-05 12:50:09 -0700 (Fri, 05 Nov 2010) | 13 lines

    Fix a use-after-free bug for extended IRQ resource[1].  When _PRS buffer is
    copied as a template for _SRS, a string pointer for descriptor name is also
    copied and it becomes stale as soon as it gets de-allocated[2].  Now _CRS is
    used as a template for _SRS as ACPI specification suggests if it is usable.

    The template from _PRS is still utilized but only when _CRS is not available
    or broken.  To avoid use-after-free the problem in this case, however, only
    mandatory fields are copied, optional data is removed, and structure length
    is adjusted accordingly.

    Reported by:    hps[1]
    Analyzed by:    avg[2]
    Tested by:      hps

This also fixes reading past the end of a structure as detected by KASAN.


(martin)
diff -r1.22 -r1.22.26.1 src/sys/dev/acpi/acpi_pci_link.c

cvs diff -r1.22 -r1.22.26.1 src/sys/dev/acpi/acpi_pci_link.c (expand / switch to unified diff)

--- src/sys/dev/acpi/acpi_pci_link.c 2014/09/14 19:54:05 1.22
+++ src/sys/dev/acpi/acpi_pci_link.c 2020/03/08 11:03:19 1.22.26.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: acpi_pci_link.c,v 1.22 2014/09/14 19:54:05 mrg Exp $ */ 1/* $NetBSD: acpi_pci_link.c,v 1.22.26.1 2020/03/08 11:03:19 martin Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 4 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE. 26 * SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.22 2014/09/14 19:54:05 mrg Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.22.26.1 2020/03/08 11:03:19 martin Exp $");
31 31
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/malloc.h> 33#include <sys/malloc.h>
34#include <sys/queue.h> 34#include <sys/queue.h>
35#include <sys/reboot.h> 35#include <sys/reboot.h>
36#include <sys/systm.h> 36#include <sys/systm.h>
37 37
38#include <dev/acpi/acpireg.h> 38#include <dev/acpi/acpireg.h>
39#include <dev/acpi/acpivar.h> 39#include <dev/acpi/acpivar.h>
40 40
41#include <dev/pci/pcireg.h> 41#include <dev/pci/pcireg.h>
42 42
43#include "opt_acpi.h" 43#include "opt_acpi.h"
@@ -245,26 +245,27 @@ link_add_crs(ACPI_RESOURCE *res, void *c @@ -245,26 +245,27 @@ link_add_crs(ACPI_RESOURCE *res, void *c
245 break; 245 break;
246 default: 246 default:
247 req->res_index++; 247 req->res_index++;
248 } 248 }
249 return (AE_OK); 249 return (AE_OK);
250} 250}
251 251
252/* 252/*
253 * Populate the set of possible IRQs for each device. 253 * Populate the set of possible IRQs for each device.
254 */ 254 */
255static ACPI_STATUS 255static ACPI_STATUS
256link_add_prs(ACPI_RESOURCE *res, void *context) 256link_add_prs(ACPI_RESOURCE *res, void *context)
257{ 257{
 258 ACPI_RESOURCE *tmp;
258 struct link_res_request *req; 259 struct link_res_request *req;
259 struct link *link; 260 struct link *link;
260 uint8_t *irqs = NULL; 261 uint8_t *irqs = NULL;
261 uint32_t *ext_irqs = NULL; 262 uint32_t *ext_irqs = NULL;
262 int i, is_ext_irq = 1; 263 int i, is_ext_irq = 1;
263 264
264 req = (struct link_res_request *)context; 265 req = (struct link_res_request *)context;
265 switch (res->Type) { 266 switch (res->Type) {
266 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 267 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
267 switch (req->in_dpf) { 268 switch (req->in_dpf) {
268 case DPF_OUTSIDE: 269 case DPF_OUTSIDE:
269 /* We've started the first DPF. */ 270 /* We've started the first DPF. */
270 req->in_dpf = DPF_FIRST; 271 req->in_dpf = DPF_FIRST;
@@ -291,52 +292,48 @@ link_add_prs(ACPI_RESOURCE *res, void *c @@ -291,52 +292,48 @@ link_add_prs(ACPI_RESOURCE *res, void *c
291 if (req->in_dpf == DPF_IGNORE) 292 if (req->in_dpf == DPF_IGNORE)
292 break; 293 break;
293 294
294 KASSERT(req->link_index < req->sc->pl_num_links); 295 KASSERT(req->link_index < req->sc->pl_num_links);
295 link = &req->sc->pl_links[req->link_index]; 296 link = &req->sc->pl_links[req->link_index];
296 if (link->l_res_index == -1) { 297 if (link->l_res_index == -1) {
297 KASSERT(req->sc->pl_crs_bad); 298 KASSERT(req->sc->pl_crs_bad);
298 link->l_res_index = req->res_index; 299 link->l_res_index = req->res_index;
299 } 300 }
300 req->link_index++; 301 req->link_index++;
301 req->res_index++; 302 req->res_index++;
302 303
303 /* 304 /*
304 * Stash a copy of the resource for later use when 305 * Stash a copy of the resource for later use when doing
305 * doing _SRS. 306 * _SRS.
306 * 
307 * Note that in theory res->Length may exceed the size 
308 * of ACPI_RESOURCE, due to variable length lists in 
309 * subtypes. However, all uses of l_prs_template only 
310 * rely on lists lengths of zero or one, for which 
311 * sizeof(ACPI_RESOURCE) is sufficient space anyway. 
312 * We cannot read longer than Length bytes, in case we 
313 * read off the end of mapped memory. So we read 
314 * whichever length is shortest, Length or 
315 * sizeof(ACPI_RESOURCE). 
316 */ 307 */
317 KASSERT(res->Length >= ACPI_RS_SIZE_MIN); 308 tmp = &link->l_prs_template;
 309 if (is_ext_irq) {
 310 memcpy(tmp, res, ACPI_RS_SIZE(tmp->Data.ExtendedIrq));
318 311
319 memset(&link->l_prs_template, 0, sizeof(link->l_prs_template)); 312 /*
320 memcpy(&link->l_prs_template, res, 313 * XXX acpi_AppendBufferResource() cannot handle
321 MIN(res->Length, sizeof(link->l_prs_template))); 314 * optional data.
 315 */
 316 memset(&tmp->Data.ExtendedIrq.ResourceSource, 0,
 317 sizeof(tmp->Data.ExtendedIrq.ResourceSource));
 318 tmp->Length = ACPI_RS_SIZE(tmp->Data.ExtendedIrq);
322 319
323 if (is_ext_irq) { 
324 link->l_num_irqs = 320 link->l_num_irqs =
325 res->Data.ExtendedIrq.InterruptCount; 321 res->Data.ExtendedIrq.InterruptCount;
326 link->l_trig = res->Data.ExtendedIrq.Triggering; 322 link->l_trig = res->Data.ExtendedIrq.Triggering;
327 link->l_pol = res->Data.ExtendedIrq.Polarity; 323 link->l_pol = res->Data.ExtendedIrq.Polarity;
328 ext_irqs = res->Data.ExtendedIrq.Interrupts; 324 ext_irqs = res->Data.ExtendedIrq.Interrupts;
329 } else { 325 } else {
 326 memcpy(tmp, res, ACPI_RS_SIZE(tmp->Data.Irq));
330 link->l_num_irqs = res->Data.Irq.InterruptCount; 327 link->l_num_irqs = res->Data.Irq.InterruptCount;
331 link->l_trig = res->Data.Irq.Triggering; 328 link->l_trig = res->Data.Irq.Triggering;
332 link->l_pol = res->Data.Irq.Polarity; 329 link->l_pol = res->Data.Irq.Polarity;
333 irqs = res->Data.Irq.Interrupts; 330 irqs = res->Data.Irq.Interrupts;
334 } 331 }
335 if (link->l_num_irqs == 0) 332 if (link->l_num_irqs == 0)
336 break; 333 break;
337 334
338 /* 335 /*
339 * Save a list of the valid IRQs. Also, if all of the 336 * Save a list of the valid IRQs. Also, if all of the
340 * valid IRQs are ISA IRQs, then mark this link as 337 * valid IRQs are ISA IRQs, then mark this link as
341 * routed via an ISA interrupt. 338 * routed via an ISA interrupt.
342 */ 339 */
@@ -727,158 +724,139 @@ acpi_pci_link_add_reference(void *v, int @@ -727,158 +724,139 @@ acpi_pci_link_add_reference(void *v, int
727 sc->pl_name, bios_irq, link->l_initial_irq); 724 sc->pl_name, bios_irq, link->l_initial_irq);
728 } else if (bios_irq != link->l_bios_irq) 725 } else if (bios_irq != link->l_bios_irq)
729 printf( 726 printf(
730 "%s: BIOS IRQ %u for %d.%d.INT%c does not match " 727 "%s: BIOS IRQ %u for %d.%d.INT%c does not match "
731 "previous BIOS IRQ %u\n", 728 "previous BIOS IRQ %u\n",
732 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A', 729 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A',
733 link->l_bios_irq); 730 link->l_bios_irq);
734 ACPI_SERIAL_END(pci_link); 731 ACPI_SERIAL_END(pci_link);
735} 732}
736 733
737static ACPI_STATUS 734static ACPI_STATUS
738acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) 735acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf)
739{ 736{
740 ACPI_RESOURCE *resource, *end, newres, *resptr; 737 ACPI_RESOURCE *end, *res;
741 ACPI_BUFFER crsbuf; 
742 ACPI_STATUS status; 738 ACPI_STATUS status;
743 struct link *link; 739 struct link *link;
744 int i, in_dpf; 740 int i, in_dpf;
745 741
746 /* Fetch the _CRS. */ 742 /* Fetch the _CRS. */
747 crsbuf.Pointer = NULL; 743 srsbuf->Pointer = NULL;
748 crsbuf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 744 srsbuf->Length = ACPI_ALLOCATE_BUFFER;
749 status = AcpiGetCurrentResources(sc->pl_handle, &crsbuf); 745 status = AcpiGetCurrentResources(sc->pl_handle, srsbuf);
750 if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL) 746 if (ACPI_SUCCESS(status) && srsbuf->Pointer == NULL)
751 status = AE_NO_MEMORY; 747 status = AE_NO_MEMORY;
752 if (ACPI_FAILURE(status)) { 748 if (ACPI_FAILURE(status)) {
753 aprint_verbose("%s: Unable to fetch current resources: %s\n", 749 aprint_verbose("%s: Unable to fetch current resources: %s\n",
754 sc->pl_name, AcpiFormatException(status)); 750 sc->pl_name, AcpiFormatException(status));
755 return (status); 751 return (status);
756 } 752 }
757 753
758 /* Fill in IRQ resources via link structures. */ 754 /* Fill in IRQ resources via link structures. */
759 srsbuf->Pointer = NULL; 
760 link = sc->pl_links; 755 link = sc->pl_links;
761 i = 0; 756 i = 0;
762 in_dpf = DPF_OUTSIDE; 757 in_dpf = DPF_OUTSIDE;
763 resource = (ACPI_RESOURCE *)crsbuf.Pointer; 758 res = (ACPI_RESOURCE *)srsbuf->Pointer;
764 end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length); 759 end = (ACPI_RESOURCE *)((char *)srsbuf->Pointer + srsbuf->Length);
765 for (;;) { 760 for (;;) {
766 switch (resource->Type) { 761 switch (res->Type) {
767 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 762 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
768 switch (in_dpf) { 763 switch (in_dpf) {
769 case DPF_OUTSIDE: 764 case DPF_OUTSIDE:
770 /* We've started the first DPF. */ 765 /* We've started the first DPF. */
771 in_dpf = DPF_FIRST; 766 in_dpf = DPF_FIRST;
772 break; 767 break;
773 case DPF_FIRST: 768 case DPF_FIRST:
774 /* We've started the second DPF. */ 769 /* We've started the second DPF. */
775 panic( 770 panic(
776 "%s: Multiple dependent functions within a current resource", 771 "%s: Multiple dependent functions within a current resource",
777 __func__); 772 __func__);
778 break; 773 break;
779 } 774 }
780 resptr = NULL; 
781 break; 775 break;
782 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 776 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
783 /* We are finished with DPF parsing. */ 777 /* We are finished with DPF parsing. */
784 KASSERT(in_dpf != DPF_OUTSIDE); 778 KASSERT(in_dpf != DPF_OUTSIDE);
785 in_dpf = DPF_OUTSIDE; 779 in_dpf = DPF_OUTSIDE;
786 resptr = NULL; 
787 break; 780 break;
788 case ACPI_RESOURCE_TYPE_IRQ: 781 case ACPI_RESOURCE_TYPE_IRQ:
789 newres = link->l_prs_template; 782 res->Data.Irq.InterruptCount = 1;
790 resptr = &newres; 
791 resptr->Data.Irq.InterruptCount = 1; 
792 if (PCI_INTERRUPT_VALID(link->l_irq)) { 783 if (PCI_INTERRUPT_VALID(link->l_irq)) {
793 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS); 784 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS);
794 resptr->Data.Irq.Interrupts[0] = link->l_irq; 785 res->Data.Irq.Interrupts[0] = link->l_irq;
795 resptr->Data.Irq.Triggering = link->l_trig; 786 res->Data.Irq.Triggering = link->l_trig;
796 resptr->Data.Irq.Polarity = link->l_pol; 787 res->Data.Irq.Polarity = link->l_pol;
797 } else 788 } else
798 resptr->Data.Irq.Interrupts[0] = 0; 789 res->Data.Irq.Interrupts[0] = 0;
799 link++; 790 link++;
800 i++; 791 i++;
801 break; 792 break;
802 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 793 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
803 newres = link->l_prs_template; 794 res->Data.ExtendedIrq.InterruptCount = 1;
804 resptr = &newres; 
805 resptr->Data.ExtendedIrq.InterruptCount = 1; 
806 if (PCI_INTERRUPT_VALID(link->l_irq)) { 795 if (PCI_INTERRUPT_VALID(link->l_irq)) {
807 resptr->Data.ExtendedIrq.Interrupts[0] = 796 res->Data.ExtendedIrq.Interrupts[0] =
808 link->l_irq; 797 link->l_irq;
809 resptr->Data.ExtendedIrq.Triggering = 798 res->Data.ExtendedIrq.Triggering =
810 link->l_trig; 799 link->l_trig;
811 resptr->Data.ExtendedIrq.Polarity = link->l_pol; 800 res->Data.ExtendedIrq.Polarity = link->l_pol;
812 } else 801 } else
813 resptr->Data.ExtendedIrq.Interrupts[0] = 0; 802 res->Data.ExtendedIrq.Interrupts[0] = 0;
814 link++; 803 link++;
815 i++; 804 i++;
816 break; 805 break;
817 default: 
818 resptr = resource; 
819 } 
820 if (resptr != NULL) { 
821 status = acpi_AppendBufferResource(srsbuf, resptr); 
822 if (ACPI_FAILURE(status)) { 
823 printf("%s: Unable to build resources: %s\n", 
824 sc->pl_name, AcpiFormatException(status)); 
825 if (srsbuf->Pointer != NULL) 
826 ACPI_FREE(srsbuf->Pointer); 
827 ACPI_FREE(crsbuf.Pointer); 
828 return (status); 
829 } 
830 } 806 }
831 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) 807 if (res->Type == ACPI_RESOURCE_TYPE_END_TAG)
832 break; 808 break;
833 resource = ACPI_NEXT_RESOURCE(resource); 809 res = ACPI_NEXT_RESOURCE(res);
834 if (resource >= end) 810 if (res >= end)
835 break; 811 break;
836 } 812 }
837 ACPI_FREE(crsbuf.Pointer); 
838 return (AE_OK); 813 return (AE_OK);
839} 814}
840 815
841static ACPI_STATUS 816static ACPI_STATUS
842acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc, 817acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc,
843 ACPI_BUFFER *srsbuf) 818 ACPI_BUFFER *srsbuf)
844{ 819{
845 ACPI_RESOURCE newres; 820 ACPI_RESOURCE newres;
846 ACPI_STATUS status; 821 ACPI_STATUS status;
847 struct link *link; 822 struct link *link;
848 int i; 823 int i;
849 824
850 /* Start off with an empty buffer. */ 825 /* Start off with an empty buffer. */
851 srsbuf->Pointer = NULL; 826 srsbuf->Pointer = NULL;
852 link = sc->pl_links; 827 link = sc->pl_links;
853 for (i = 0; i < sc->pl_num_links; i++) { 828 for (i = 0; i < sc->pl_num_links; i++) {
854 829
855 /* Add a new IRQ resource from each link. */ 830 /* Add a new IRQ resource from each link. */
856 link = &sc->pl_links[i]; 831 link = &sc->pl_links[i];
857 newres = link->l_prs_template; 832 if (link->l_prs_template.Type == ACPI_RESOURCE_TYPE_IRQ) {
858 if (newres.Type == ACPI_RESOURCE_TYPE_IRQ) { 
859 833
860 /* Build an IRQ resource. */ 834 /* Build an IRQ resource. */
 835 bcopy(&link->l_prs_template, &newres,
 836 ACPI_RS_SIZE(newres.Data.Irq));
861 newres.Data.Irq.InterruptCount = 1; 837 newres.Data.Irq.InterruptCount = 1;
862 if (PCI_INTERRUPT_VALID(link->l_irq)) { 838 if (PCI_INTERRUPT_VALID(link->l_irq)) {
863 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS); 839 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS);
864 newres.Data.Irq.Interrupts[0] = link->l_irq; 840 newres.Data.Irq.Interrupts[0] = link->l_irq;
865 newres.Data.Irq.Triggering = link->l_trig; 841 newres.Data.Irq.Triggering = link->l_trig;
866 newres.Data.Irq.Polarity = link->l_pol; 842 newres.Data.Irq.Polarity = link->l_pol;
867 } else 843 } else
868 newres.Data.Irq.Interrupts[0] = 0; 844 newres.Data.Irq.Interrupts[0] = 0;
869 } else { 845 } else {
870 846
871 /* Build an ExtIRQ resuorce. */ 847 /* Build an ExtIRQ resuorce. */
 848 bcopy(&link->l_prs_template, &newres,
 849 ACPI_RS_SIZE(newres.Data.ExtendedIrq));
872 newres.Data.ExtendedIrq.InterruptCount = 1; 850 newres.Data.ExtendedIrq.InterruptCount = 1;
873 if (PCI_INTERRUPT_VALID(link->l_irq)) { 851 if (PCI_INTERRUPT_VALID(link->l_irq)) {
874 newres.Data.ExtendedIrq.Interrupts[0] = 852 newres.Data.ExtendedIrq.Interrupts[0] =
875 link->l_irq; 853 link->l_irq;
876 newres.Data.ExtendedIrq.Triggering = 854 newres.Data.ExtendedIrq.Triggering =
877 link->l_trig; 855 link->l_trig;
878 newres.Data.ExtendedIrq.Polarity = 856 newres.Data.ExtendedIrq.Polarity =
879 link->l_pol; 857 link->l_pol;
880 } else { 858 } else {
881 newres.Data.ExtendedIrq.Interrupts[0] = 0; 859 newres.Data.ExtendedIrq.Interrupts[0] = 0;
882 } 860 }
883 } 861 }
884 862