DF-4505 / fix.diff
--- a/sys/dev/misc/ipmi/ipmi.c +++ b/sys/dev/misc/ipmi/ipmi.c @@ -77,6 +77,16 @@ .d_kqfilter = ipmi_kqfilter, }; +/* + * Cap on outstanding requests per open /dev/ipmiN handle. Each request + * kmallocs sizeof(struct ipmi_request) + ir_requestlen + IPMI_MAX_RX + * bytes; the interface kthread drains the queue serially, so without a + * cap an operator-group user can park an unbounded backlog of in-flight + * requests with an async IPMICTL_SEND_COMMAND flood and exhaust kernel + * memory ("panic: ipmi: malloc limit exceeded"). + */ +#define IPMI_MAX_REQUESTS 128 + static int ipmi_watchdog_sysctl_enable(SYSCTL_HANDLER_ARGS); static int ipmi_watchdog_sysctl_period(SYSCTL_HANDLER_ARGS); @@ -408,11 +418,22 @@ return (error); } IPMI_LOCK(sc); + if (dev->ipmi_requests >= IPMI_MAX_REQUESTS) { + /* Too many requests still in flight for this handle. */ + IPMI_UNLOCK(sc); + ipmi_free_request(kreq); + return (EBUSY); + } dev->ipmi_requests++; error = sc->ipmi_enqueue_request(sc, kreq); - IPMI_UNLOCK(sc); - if (error) + if (error != 0) { + /* Not queued: this request will never complete. */ + dev->ipmi_requests--; + IPMI_UNLOCK(sc); + ipmi_free_request(kreq); return (error); + } + IPMI_UNLOCK(sc); break; #ifdef IPMICTL_SEND_COMMAND_32 case IPMICTL_RECEIVE_MSG_TRUNC_32: |