DF-4777 / fix.diff
diff -ur a/sys/dev/misc/ipmi/ipmi.c b/sys/dev/misc/ipmi/ipmi.c --- a/sys/dev/misc/ipmi/ipmi.c +++ b/sys/dev/misc/ipmi/ipmi.c @@ -446,6 +446,14 @@ return (error); } len = kreq->ir_replylen + 1; + /* + * ir_replylen is transport-reported (BMC-controlled byte + * count) and must never be trusted past the allocated + * reply buffer (IPMI_MAX_RX for ioctl requests). + */ + if (kreq->ir_replybuflen != 0 && + len > kreq->ir_replybuflen + 1) + len = kreq->ir_replybuflen + 1; if (recv->msg.data_len < len && (cmd == IPMICTL_RECEIVE_MSG #ifdef IPMICTL_RECEIVE_MSG_32 diff -ur a/sys/dev/misc/ipmi/ipmi_kcs.c b/sys/dev/misc/ipmi/ipmi_kcs.c --- a/sys/dev/misc/ipmi/ipmi_kcs.c +++ b/sys/dev/misc/ipmi/ipmi_kcs.c @@ -429,6 +429,13 @@ } i++; } + /* + * i counts every byte the BMC streamed in READ state; it is not + * bounded by our buffer. Clamp so downstream consumers can never + * read past ir_reply[]. + */ + if (i > req->ir_replybuflen) + i = req->ir_replybuflen; req->ir_replylen = i; #ifdef KCS_DEBUG device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i); diff -ur a/sys/dev/misc/ipmi/ipmi_smic.c b/sys/dev/misc/ipmi/ipmi_smic.c --- a/sys/dev/misc/ipmi/ipmi_smic.c +++ b/sys/dev/misc/ipmi/ipmi_smic.c @@ -338,6 +338,9 @@ /* Terminate the transfer. */ if (!smic_read_end(sc)) return (0); + /* i counts every byte the BMC streamed; clamp to the buffer. */ + if (i > req->ir_replybuflen) + i = req->ir_replybuflen; req->ir_replylen = i; #ifdef SMIC_DEBUG device_printf(sc->ipmi_dev, "SMIC: READ finished (%d bytes)\n", i); |