⬢ DragonFlyBSD Kernel Audit
DF-2906 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/libmchain/subr_mchain.c
+++ b/sys/kern/libmchain/subr_mchain.c
@@ -73,6 +73,8 @@
 	struct mbuf *m;
 
 	m = m_gethdr(M_WAITOK, MT_DATA);
+	if (m == NULL)
+		return ENOBUFS;
 	m->m_pkthdr.rcvif = NULL;
 	m->m_len = 0;
 	mb_initm(mbp, m);
@@ -129,6 +131,8 @@
 	m = mbp->mb_cur;
 	if (mbp->mb_mleft < size) {
 		mn = m_get(M_WAITOK, MT_DATA);
+		if (mn == NULL)
+			return NULL;
 		mbp->mb_cur = m->m_next = mn;
 		m = mn;
 		m->m_len = 0;
@@ -206,6 +210,8 @@
 			if (m->m_next == NULL)
 				m->m_next = m_getc(size, M_WAITOK, MT_DATA);
 			m = m->m_next;
+			if (m == NULL)
+				return ENOBUFS;
 			mleft = M_TRAILINGSPACE(m);
 			continue;
 		}
@@ -306,6 +312,8 @@
 	struct mbuf *m;
 
 	m = m_gethdr(M_WAITOK, MT_DATA);
+	if (m == NULL)
+		return ENOBUFS;
 	m->m_pkthdr.rcvif = NULL;
 	m->m_len = 0;
 	md_initm(mdp, m);
@@ -327,6 +335,8 @@
 		m_freem(mdp->md_top);
 		mdp->md_top = NULL;
 	}
+	mdp->md_cur = NULL;
+	mdp->md_pos = NULL;
 }
 
 /*
@@ -512,10 +522,30 @@
 {
 	struct mbuf *m = mdp->md_cur, *rm;
 
+	int remain = 0;
+	struct mbuf *x;
+	u_char *pos;
+
+	/* Verify the chain actually holds size bytes BEFORE m_copym
+	 * (m_copym KASSERTs on INVARIANTS kernels for oversized requests
+	 * and silently truncates on production kernels). */
+	x = m;
+	pos = mdp->md_pos;
+	while (x) {
+		remain += mtod(x, u_char*) + x->m_len - pos;
+		pos = mtod(x, u_char*);
+		x = x->m_next;
+	}
+	if (size > remain)
+		return EBADRPC;
+
 	rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAITOK);
 	if (rm == NULL)
 		return EBADRPC;
-	md_get_mem(mdp, NULL, size, MB_MZERO);
+	if (md_get_mem(mdp, NULL, size, MB_MZERO) != 0) {
+		m_freem(rm);
+		return EBADRPC;
+	}
 	*ret = rm;
 	return 0;
 }