DF-4978 / 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_ssif.c b/sys/dev/misc/ipmi/ipmi_ssif.c --- a/sys/dev/misc/ipmi/ipmi_ssif.c +++ b/sys/dev/misc/ipmi/ipmi_ssif.c @@ -300,7 +300,13 @@ } done: /* Save the total length and return success. */ + /* + * len accumulates every BMC-reported block byte count; clamp it + * to the reply buffer or the ipmi.c consumer over-reads the heap. + */ + if (len > req->ir_replybuflen) + len = req->ir_replybuflen; req->ir_replylen = len; smbus_release_bus(smbus, dev); return (1); |