Date: Wed, 24 Nov 1999 18:09:18 +0900 (JST) From: Jun-ichiro itojun Hagino <itojun@itojun.org> To: FreeBSD-gnats-submit@freebsd.org Cc: green@freebsd.org, core@kame.net Subject: kern/15071: tcp fails to handle TIME_WAIT special case Message-ID: <199911240909.SAA03218@coconut.itojun.org>
index | next in thread | raw e-mail
>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
home |
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199911240909.SAA03218>
