Panic: UDP header not in one mbuf

Matthew Dillon dillon at apollo.backplane.com
Mon Aug 23 14:25:17 PDT 2004


:I am not sure if this is the proper mailing list for this question; if
:not, please direct me accordingly.
:
:On a DragonFly 1.1-Current machine (cvsupped and built 8/19/2004) I
:receive the following output after a panic (with DDB enabled in kernel):
:
:panic: UDP header not in one mbuf
:...
:
:I have been having issues of this nature for a while - I suspect an
:issue I am having with bind (named) crashing is related to this.
:
:The machines are Supermicro 6013P-8 with dual P4 (Xeon) procs. ACPI is
:disabled, HTT is not. The machines process a decent volume (65k pieces
:daily) of email and use mimedefang/spamassassin/sendmail along with a
:local caching instance of named.

    Sven, please try this patch.  After examining the code path I found
    a hole where an embedded ip_len which is smaller then the actual
    packet survives the length test in ip_demux(), which means it can hit
    the assertion in udp_input().

						-Matt

Index: ip_demux.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_demux.c,v
retrieving revision 1.26
diff -u -r1.26 ip_demux.c
--- ip_demux.c	3 Aug 2004 00:04:13 -0000	1.26
+++ ip_demux.c	23 Aug 2004 21:21:14 -0000
@@ -109,6 +109,7 @@
 {
 	struct ip *ip;
 	int iphlen;
+	int iplen;
 	struct tcphdr *th;
 	struct udphdr *uh;
 	struct mbuf *m = *mptr;
@@ -142,6 +143,7 @@
 	 * first mbuf must entirely contain the extended IP header.
 	 */
 	iphlen = ip->ip_hl << 2;
+	iplen = ntohs(ip->ip_len);
 	if (iphlen < sizeof(struct ip)) {	/* minimum header length */
 		ipstat.ips_badhlen++;
 		m_freem(m);
@@ -161,10 +163,20 @@
 	 * The TCP/IP or UDP/IP header must be entirely contained within
 	 * the first fragment of a packet.  Packet filters will break if they
 	 * aren't.
+	 *
+	 * Since the packet will be trimmed to ip_len we must also make sure
+	 * the potentially trimmed down length is still sufficient to hold
+	 * the header(s).
 	 */
 	if ((ntohs(ip->ip_off) & IP_OFFMASK) == 0) {
 		switch (ip->ip_p) {
 		case IPPROTO_TCP:
+			if (iplen < iphlen + sizeof(struct tcphdr)) {
+				++tcpstat.tcps_rcvshort;
+				m_freem(m);
+				*mptr = NULL;
+				return (NULL);
+			}
 			if (m->m_len < iphlen + sizeof(struct tcphdr)) {
 				m = m_pullup(m, iphlen + sizeof(struct tcphdr));
 				if (m == NULL) {
@@ -176,6 +188,12 @@
 			}
 			break;
 		case IPPROTO_UDP:
+			if (iplen < iphlen + sizeof(struct udphdr)) {
+				++udpstat.udps_hdrops;
+				m_freem(m);
+				*mptr = NULL;
+				return (NULL);
+			}
 			if (m->m_len < iphlen + sizeof(struct udphdr)) {
 				m = m_pullup(m, iphlen + sizeof(struct udphdr));
 				if (m == NULL) {
@@ -187,6 +205,12 @@
 			}
 			break;
 		default:
+			if (iplen < iphlen) {
+				++ipstat.ips_badlen;
+				m_freem(m);
+				*mptr = NULL;
+				return (NULL);
+			}
 			break;
 		}
 	}





More information about the Kernel mailing list