DF-5276 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | --- a/sys/bus/pci/pci.c +++ b/sys/bus/pci/pci.c @@ -1098,6 +1098,7 @@ "pci%d:%d:%d:%d: invalid VPD data, remain %#x\n", cfg->domain, cfg->bus, cfg->slot, cfg->func, remain); + break; } name = byte & 0x7f; } else { @@ -1106,6 +1107,12 @@ } switch (name) { case 0x2: /* String */ + if (remain == 0) { + /* zero-length ident: state 1 would + * write unboundedly past kmalloc(1) */ + state = -1; + break; + } cfg->vpd.vpd_ident = kmalloc(remain + 1, M_DEVBUF, M_WAITOK); i = 0; @@ -1187,6 +1194,12 @@ sizeof(*cfg->vpd.vpd_ros[off].value), M_DEVBUF, M_WAITOK); remain -= 3; + if (remain < 0) { + /* header longer than item: `remain == 0` + * could never fire again */ + state = -1; + break; + } i = 0; /* keep in sync w/ state 3's transistions */ if (dflen == 0 && remain == 0) @@ -1258,6 +1271,12 @@ sizeof(*cfg->vpd.vpd_w[off].value), M_DEVBUF, M_WAITOK); remain -= 3; + if (remain < 0) { + /* header longer than item: `remain == 0` + * could never fire again */ + state = -1; + break; + } i = 0; /* keep in sync w/ state 6's transistions */ if (dflen == 0 && remain == 0) @@ -1301,6 +1320,7 @@ kfree(cfg->vpd.vpd_ros[off].value, M_DEVBUF); kfree(cfg->vpd.vpd_ros, M_DEVBUF); cfg->vpd.vpd_ros = NULL; + cfg->vpd.vpd_rocnt = 0; } } if (state < -1) { @@ -1316,6 +1336,7 @@ kfree(cfg->vpd.vpd_w[off].value, M_DEVBUF); kfree(cfg->vpd.vpd_w, M_DEVBUF); cfg->vpd.vpd_w = NULL; + cfg->vpd.vpd_wcnt = 0; } } cfg->vpd.vpd_cached = 1; @@ -1351,10 +1372,14 @@ if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0) pci_read_vpd(device_get_parent(dev), cfg); + if (cfg->vpd.vpd_ros == NULL) + return (ENXIO); + for (i = 0; i < cfg->vpd.vpd_rocnt; i++) if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword, sizeof(cfg->vpd.vpd_ros[i].keyword)) == 0) { *vptr = cfg->vpd.vpd_ros[i].value; + break; } if (i != cfg->vpd.vpd_rocnt) @@ -2144,13 +2169,19 @@ devlist_head = &pci_devq; if (dinfo->cfg.vpd.vpd_reg) { - kfree(dinfo->cfg.vpd.vpd_ident, M_DEVBUF); - for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++) - kfree(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF); - kfree(dinfo->cfg.vpd.vpd_ros, M_DEVBUF); - for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++) - kfree(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); - kfree(dinfo->cfg.vpd.vpd_w, M_DEVBUF); + if (dinfo->cfg.vpd.vpd_ident != NULL) + kfree(dinfo->cfg.vpd.vpd_ident, M_DEVBUF); + if (dinfo->cfg.vpd.vpd_ros != NULL) { + for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++) + kfree(dinfo->cfg.vpd.vpd_ros[i].value, + M_DEVBUF); + kfree(dinfo->cfg.vpd.vpd_ros, M_DEVBUF); + } + if (dinfo->cfg.vpd.vpd_w != NULL) { + for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++) + kfree(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); + kfree(dinfo->cfg.vpd.vpd_w, M_DEVBUF); + } } STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); kfree(dinfo, M_DEVBUF); |