From owner-freebsd-bugs Wed Nov 24 1:10: 7 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id CF53914FDF for ; Wed, 24 Nov 1999 01:10:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id BAA06057; Wed, 24 Nov 1999 01:10:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from coconut.itojun.org (coconut.itojun.org [210.160.95.97]) by hub.freebsd.org (Postfix) with ESMTP id 748EA14FDC; Wed, 24 Nov 1999 01:09:24 -0800 (PST) (envelope-from itojun@itojun.org) Received: (from itojun@localhost) by coconut.itojun.org (8.9.3+3.2W/3.7W) id SAA03218; Wed, 24 Nov 1999 18:09:18 +0900 (JST) Message-Id: <199911240909.SAA03218@coconut.itojun.org> Date: Wed, 24 Nov 1999 18:09:18 +0900 (JST) From: Jun-ichiro itojun Hagino Reply-To: itojun@itojun.org To: FreeBSD-gnats-submit@freebsd.org Cc: green@freebsd.org, core@kame.net X-Send-Pr-Version: 3.2 Subject: kern/15071: tcp fails to handle TIME_WAIT special case Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 15071 >Category: kern >Synopsis: tcp fails to handle TIME_WAIT special case >Confidential: no >Severity: critical >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Nov 24 01:10:00 PST 1999 >Closed-Date: >Last-Modified: >Originator: Jun-ichiro itojun Hagino >Release: FreeBSD-current >Organization: itojun.org >Environment: As far as I've checked, HEAD, RELENG_3 and RELENG_2 are affected. >Description: in tcp_input() (sys/netinet/tcp_input.c) there are two places "goto findpcb" is used. They are for aceepting new connction while tcb is in TIME_WAIT state. However, because FreeBSD tcp_input strips off mbuf until tcp data segment at the following line, "goto findpcb" attempt will never success. /* * 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); >How-To-Repeat: Due to this we KAME team encountered panic in IPsec policy management engine. I dunno if there's any problem with normal FreeBSD. Serious cracker may try to hand-cruft tcp data segment that contains wrong tcp header (to be uesd when "goto findpcb" is kicked). >Fix: There are two possible fixes to this. I prefer the latter one as we will need to introduce the latter one anyways for IPv6 support. Short term fix will be to compute m_data and m_len back to the original: Index: tcp_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.96 diff -c -r1.96 tcp_input.c *** tcp_input.c 1999/10/09 20:42:15 1.96 --- tcp_input.c 1999/11/24 08:55:01 *************** *** 286,291 **** --- 286,292 ---- register int tiflags; struct socket *so = 0; int todrop, acked, ourfinisacked, needoutput = 0; + int hdroptlen; struct in_addr laddr; int dropsocket = 0; int iss = 0; *************** *** 376,383 **** /* * 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); /* * Locate pcb for segment. --- 377,385 ---- /* * Drop TCP, IP headers and TCP options. */ ! hdroptlen = sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); ! m->m_data += hdroptlen; ! m->m_len -= hdroptlen; /* * Locate pcb for segment. *************** *** 1059,1064 **** --- 1061,1068 ---- goto dropwithreset; if (CC_GT(to.to_cc, tp->cc_recv)) { tp = tcp_close(tp); + m->m_data -= hdroptlen; + m->m_len += hdroptlen; goto findpcb; } else *************** *** 1282,1287 **** --- 1286,1293 ---- SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { iss = tp->snd_nxt + TCP_ISSINCR; tp = tcp_close(tp); + m->m_data -= hdroptlen; + m->m_len += hdroptlen; goto findpcb; } /* Long-term (and more clean) fix would be to avoid modifying m_len and m_data. Index: tcp_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.96 diff -c -r1.96 tcp_input.c *** tcp_input.c 1999/10/09 20:42:15 1.96 --- tcp_input.c 1999/11/24 09:00:42 *************** *** 112,118 **** static void tcp_dooptions __P((struct tcpcb *, u_char *, int, struct tcpiphdr *, struct tcpopt *)); static void tcp_pulloutofband __P((struct socket *, ! struct tcpiphdr *, struct mbuf *)); static int tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *)); static void tcp_xmit_timer __P((struct tcpcb *, int)); --- 112,118 ---- static void tcp_dooptions __P((struct tcpcb *, u_char *, int, struct tcpiphdr *, struct tcpopt *)); static void tcp_pulloutofband __P((struct socket *, ! struct tcpiphdr *, struct mbuf *, int)); static int tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *)); static void tcp_xmit_timer __P((struct tcpcb *, int)); *************** *** 286,291 **** --- 286,292 ---- register int tiflags; struct socket *so = 0; int todrop, acked, ourfinisacked, needoutput = 0; + int hdroptlen = 0; struct in_addr laddr; int dropsocket = 0; int iss = 0; *************** *** 374,383 **** NTOHS(ti->ti_urp); /* ! * 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); /* * Locate pcb for segment. --- 375,383 ---- NTOHS(ti->ti_urp); /* ! * Compute mbuf offset for TCP data segment. */ ! hdroptlen = sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); /* * Locate pcb for segment. *************** *** 673,678 **** --- 673,679 ---- /* * Add data to socket buffer. */ + m_adj(m, hdroptlen); sbappend(&so->so_rcv, m); sorwakeup(so); if (tcp_delack_enabled) { *************** *** 1240,1246 **** tcpstat.tcps_rcvpartduppack++; tcpstat.tcps_rcvpartdupbyte += todrop; } ! m_adj(m, todrop); ti->ti_seq += todrop; ti->ti_len -= todrop; if (ti->ti_urp > todrop) --- 1241,1247 ---- tcpstat.tcps_rcvpartduppack++; tcpstat.tcps_rcvpartdupbyte += todrop; } ! hdroptlen += todrop; /* drop from head afterwards */ ti->ti_seq += todrop; ti->ti_len -= todrop; if (ti->ti_urp > todrop) *************** *** 1725,1731 **** && (so->so_options & SO_OOBINLINE) == 0 #endif ) ! tcp_pulloutofband(so, ti, m); } else /* * If no out of band data is expected, --- 1726,1732 ---- && (so->so_options & SO_OOBINLINE) == 0 #endif ) ! tcp_pulloutofband(so, ti, m, hdroptlen); } else /* * If no out of band data is expected, *************** *** 1746,1751 **** --- 1747,1753 ---- */ if ((ti->ti_len || (tiflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { + m_adj(m, hdroptlen); TCP_REASS(tp, ti, m, so, tiflags); /* * Note the amount of data that peer has sent into *************** *** 2036,2047 **** * sequencing purposes. */ static void ! tcp_pulloutofband(so, ti, m) struct socket *so; struct tcpiphdr *ti; register struct mbuf *m; { ! int cnt = ti->ti_urp - 1; while (cnt >= 0) { if (m->m_len > cnt) { --- 2038,2050 ---- * sequencing purposes. */ static void ! tcp_pulloutofband(so, ti, m, off) struct socket *so; struct tcpiphdr *ti; register struct mbuf *m; + int off; { ! int cnt = off + ti->ti_urp - 1; while (cnt >= 0) { if (m->m_len > cnt) { >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message