--- a/sys/bus/isa/pnpparse.c +++ b/sys/bus/isa/pnpparse.c @@ -92,6 +92,20 @@ * Got a compatible device id resource. * Should keep a list of compat ids in the device. */ + /* + * The declared length is card-controlled and is + * never validated against the fixed offsets the + * handlers below dereference; a short/zero length + * would read (and for IO_RANGE write) past the + * descriptor -- and, for a descriptor at the end of + * the card stream buffer, past the heap allocation. + * Validate len per tag; skip malformed descriptors. + */ + if (len < 4) { + pnp_printf(id, "bogus compat device length %d\n", + len); + break; + } bcopy(res, &compat_id, 4); if (isa_get_compatid(dev) == 0) isa_set_compatid(dev, compat_id); @@ -102,6 +116,11 @@ pnp_printf(id, "too many irqs\n"); return (1); } + if (len < 2) { + pnp_printf(id, "bogus irq format length %d\n", + len); + break; + } if (I16(res) == 0) { /* a null descriptor */ config->ic_irqmask[config->ic_nirq] = 0; @@ -120,6 +139,11 @@ pnp_printf(id, "too many drqs\n"); return (1); } + if (len < 1) { + pnp_printf(id, "bogus dma format length %d\n", + len); + break; + } if (res[0] == 0) { /* a null descriptor */ config->ic_drqmask[config->ic_ndrq] = 0; @@ -138,6 +162,11 @@ pnp_printf(id, "too many ports\n"); return (1); } + if (len < 7) { + pnp_printf(id, "bogus io range length %d\n", + len); + break; + } if (res[6] == 0) { /* a null descriptor */ config->ic_port[config->ic_nport].ir_start = 0; @@ -175,6 +204,11 @@ pnp_printf(id, "too many ports\n"); return (1); } + if (len < 3) { + pnp_printf(id, "bogus fixed io range length %d\n", + len); + break; + } if (res[2] == 0) { /* a null descriptor */ config->ic_port[config->ic_nport].ir_start = 0; @@ -239,6 +273,11 @@ pnp_printf(id, "too many memory ranges\n"); return (1); } + if (len < 9) { + pnp_printf(id, "bogus memory range length %d\n", + len); + break; + } if (I16(res + 7) == 0) { /* a null descriptor */ config->ic_mem[config->ic_nmem].ir_start = 0; @@ -275,6 +314,11 @@ pnp_printf(id, "too many memory ranges\n"); return (1); } + if (len < 17) { + pnp_printf(id, "bogus memory32 range length %d\n", + len); + break; + } if (I32(res + 13) == 0) { /* a null descriptor */ config->ic_mem[config->ic_nmem].ir_start = 0; @@ -305,6 +349,11 @@ pnp_printf(id, "too many memory ranges\n"); return (1); } + if (len < 9) { + pnp_printf(id, "bogus fixed memory32 length %d\n", + len); + break; + } if (I32(res + 5) == 0) { /* a null descriptor */ config->ic_mem[config->ic_nmem].ir_start = 0;