| Summary: | tcp_input() fails to update m->m_pkthdr.len | ||
|---|---|---|---|
| Product: | Base System | Reporter: | Archie Cobbs <archie> |
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | 3.3-STABLE | ||
| Hardware: | Any | ||
| OS: | Any | ||
This bug is fixed in 4.0-current thanks to the IPv6 integration. However, it remains in 3.4-stable.. below is a patch that fixes it with some KASSERT's to insure that the M_PKTHDR assumptions are correct. -Archie ___________________________________________________________________________ Archie Cobbs * Whistle Communications, Inc. * http://www.whistle.com Index: sys/netinet/ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.111.2.5 diff -u -r1.111.2.5 ip_input.c --- ip_input.c 2000/01/18 16:03:55 1.111.2.5 +++ ip_input.c 2000/01/26 23:57:18 @@ -909,9 +909,14 @@ (void) m_free(dtom(fp)); m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); - /* some debugging cruft by sklower, below, will go away soon */ - if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ + + /* + * Recompute total packet length + */ + KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__)); + { register int plen = 0; + for (t = m; m; m = m->m_next) plen += m->m_len; t->m_pkthdr.len = plen; Index: sys/netinet/tcp_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.82.2.3 diff -u -r1.82.2.3 tcp_input.c --- tcp_input.c 1999/10/14 11:49:38 1.82.2.3 +++ tcp_input.c 2000/01/26 23:57:22 @@ -292,6 +292,8 @@ short ostate = 0; #endif + KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__)); + bzero((char *)&to, sizeof(to)); tcpstat.tcps_rcvtotal++; @@ -371,8 +373,14 @@ /* * Drop TCP, IP headers and TCP options. */ - m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + { + const int diff = sizeof(struct tcpiphdr) + off + - sizeof(struct tcphdr); + + m->m_data += diff; + m->m_len -= diff; + m->m_pkthdr.len -= diff; + } /* * Locate pcb for segment. @@ -1954,8 +1962,11 @@ struct tcpiphdr *ti; register struct mbuf *m; { + struct mbuf *m0 = m; int cnt = ti->ti_urp - 1; + KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__)); + while (cnt >= 0) { if (m->m_len > cnt) { char *cp = mtod(m, caddr_t) + cnt; @@ -1965,6 +1976,7 @@ tp->t_oobflags |= TCPOOB_HAVEDATA; bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); m->m_len--; + m0->m_pkthdr.len--; return; } cnt -= m->m_len; State Changed From-To: open->closed RELENG_3 no longer supported for anything but the most critical fixes. |
See sys/netinet/tcp_input.c, line 376: /* * Drop TCP, IP headers and TCP options. */ m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); Notice that m->m_pkthdr.len is not updated, and therefore the mbuf becomes inconsistent. Apparently this doesn't matter much in normal use. However, netgraph(4) is strict about checking the consistency of mbufs and the above omission causes a panic later on. Fix: if ((m->m_flags & M_PKTHDR) != 0) m->m_pkthdr.len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); [ Can we always assume ((m->m_flags & M_PKTHDR) != 0) here?? ] How-To-Repeat: Input TCP data