--- a/sys/net/sppp/if_spppsubr.c +++ b/sys/net/sppp/if_spppsubr.c @@ -1530,6 +1530,21 @@ break; case CONF_NAK: case CONF_REJ: + /* + * The RCN handlers do "len -= 4" and kmalloc(len). + * A peer-supplied h->len < 4 makes that negative, + * which becomes a huge size_t in kmalloc() and + * panics the allocator (round_page() wraps to 0 and + * the degenerate oversized allocation corrupts the + * kernel map). CONF_REQ above has the same guard. + */ + if (len < 4) { + if (debug) + log(-1, SPP_FMT "%s invalid conf-nak/rej length %d\n", + SPP_ARGS(ifp), cp->name, len); + IFNET_STAT_INC(ifp, ierrors, 1); + break; + } if (h->ident != sp->confid[cp->protoidx]) { if (debug) log(-1, SPP_FMT "%s id mismatch 0x%x != 0x%x\n", @@ -2970,6 +2985,21 @@ desiredcomp = p[2] << 8 | p[3]; /* We only support VJ */ if (desiredcomp == IPCP_COMP_VJ) { + /* + * sl_compress_init() writes tstate[i] for + * i = max_state..1 although tstate[] has + * only MAX_STATES entries -- a peer-supplied + * Max-Slot-Id above MAX_STATES-1 smashes + * ~32KB past the struct slcompress heap + * allocation. NAK anything out of range. + */ + if (p[4] >= MAX_STATES) { + if (debug) + log(-1, "max-slot %d [invalid] ", + p[4]); + p[4] = sp->ipcp.max_state; + break; + } if (debug) log(-1, "VJ [ack] "); sp->ipcp.flags |= IPCP_VJ; @@ -3164,6 +3194,9 @@ log(-1, "[wantcomp %#04x] ", desiredcomp); if (desiredcomp == IPCP_COMP_VJ) { + /* see sppp_ipcp_RCR: clamp max-slot */ + if (p[4] >= MAX_STATES) + break; sl_compress_init(sp->pp_comp, p[4]); sp->ipcp.max_state = p[4]; sp->ipcp.compress_cid = p[5];