From ee7990a0cff3bca73ea287a5a41d65b68630f45d Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 28 Aug 2004 18:33:03 +0000 Subject: [PATCH] Since ip_input() truncates the packet to ip->ip_len prior to entering the protocol stack, ip_demux must incorporate an ip_len check in its tcp/udp prechecks to avoid an assertion in the tcp/udp stacks if the packet is malformed. This is a temporary hack until Jeff and I can come up with a better way to do per-protocol mbuf checks. Basically the issue involved is that we want to pull up the entire tcp/udp/etc... header in order to be able to trivially demux an IP packet (choose which protocol thread to route it to). Since we have to m_pullup the packet in the demux we would rather do all header length checks in the demux as well so as not have to repeat them in the protocol code. Reported-by: Sven Willenberger In-discussion-with: Jeffrey Hsu --- sys/netinet/ip_demux.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/sys/netinet/ip_demux.c b/sys/netinet/ip_demux.c index 9f5cd3e4a9..ed16adfd84 100644 --- a/sys/netinet/ip_demux.c +++ b/sys/netinet/ip_demux.c @@ -30,7 +30,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/netinet/ip_demux.c,v 1.26 2004/08/03 00:04:13 dillon Exp $ + * $DragonFly: src/sys/netinet/ip_demux.c,v 1.27 2004/08/28 18:33:03 dillon Exp $ */ /* @@ -109,6 +109,7 @@ ip_mport(struct mbuf **mptr) { struct ip *ip; int iphlen; + int iplen; struct tcphdr *th; struct udphdr *uh; struct mbuf *m = *mptr; @@ -142,6 +143,7 @@ ip_mport(struct mbuf **mptr) * 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 @@ ip_mport(struct mbuf **mptr) * 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 @@ ip_mport(struct mbuf **mptr) } 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 @@ ip_mport(struct mbuf **mptr) } break; default: + if (iplen < iphlen) { + ++ipstat.ips_badlen; + m_freem(m); + *mptr = NULL; + return (NULL); + } break; } } -- 2.41.0