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