⬢ DragonFlyBSD Kernel Audit
DF-3273 / fix.diff
← back to finding ↓ download raw
--- 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];