DragonFlyBSD Kernel Audit
DF-0611 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netgraph7/ng_nat.c b/sys/netgraph7/ng_nat.c
--- a/sys/netgraph7/ng_nat.c
+++ b/sys/netgraph7/ng_nat.c
@@ -689,6 +689,12 @@
 
 	m = NGI_M(item);
 
+	/* Reject anything too short to be an IP packet. */
+	if (m->m_pkthdr.len < sizeof(struct ip)) {
+		NG_FREE_ITEM(item);
+		return (EINVAL);
+	}
+
 	if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) {
 		NGI_M(item) = NULL;	/* avoid double free */
 		NG_FREE_ITEM(item);
@@ -700,6 +706,17 @@
 	c = mtod(m, char *);
 	ip = mtod(m, struct ip *);
 
+	/*
+	 * Validate ip_hl and ip_len against the actual packet before
+	 * we trust any field of the header.
+	 */
+	if (ip->ip_hl < 5 ||
+	    ntohs(ip->ip_len) < (ip->ip_hl << 2) ||
+	    ntohs(ip->ip_len) > m->m_pkthdr.len) {
+		NG_FREE_ITEM(item);
+		return (EINVAL);
+	}
+
 	KASSERT(m->m_pkthdr.len == ntohs(ip->ip_len),
 		("ng_nat: ip_len != m_pkthdr.len"));
 
@@ -722,7 +739,8 @@
 	m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len);
 
 	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
-	    ip->ip_p == IPPROTO_TCP) {
+	    ip->ip_p == IPPROTO_TCP &&
+	    ntohs(ip->ip_len) >= (u_int)(ip->ip_hl << 2) + sizeof(struct tcphdr)) {
 		struct tcphdr *th = (struct tcphdr *)((caddr_t)ip +
 		    (ip->ip_hl << 2));