| From 600ff0c24bb71482e7f0da948a931d5c5d72838a Mon Sep 17 00:00:00 2001 |
| From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> |
| Date: Tue, 13 Feb 2007 12:42:11 -0800 |
| Subject: [TCP]: Prevent pseudo garbage in SYN's advertized window |
| Message-Id: <20070213.182131.102574822.davem@davemloft.net> |
| |
| From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> |
| |
| TCP may advertize up to 16-bits window in SYN packets (no window |
| scaling allowed). At the same time, TCP may have rcv_wnd |
| (32-bits) that does not fit to 16-bits without window scaling |
| resulting in pseudo garbage into advertized window from the |
| low-order bits of rcv_wnd. This can happen at least when |
| mss <= (1<<wscale) (see tcp_select_initial_window). This patch |
| fixes the handling of SYN advertized windows (compile tested |
| only). |
| |
| In worst case (which is unlikely to occur though), the receiver |
| advertized window could be just couple of bytes. I'm not sure |
| that such situation would be handled very well at all by the |
| receiver!? Fortunately, the situation normalizes after the |
| first non-SYN ACK is received because it has the correct, |
| scaled window. |
| |
| Alternatively, tcp_select_initial_window could be changed to |
| prevent too large rcv_wnd in the first place. |
| |
| [ tcp_make_synack() has the same bug, and I've added a fix for |
| that to this patch -DaveM ] |
| |
| Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/ipv4/tcp_output.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- linux-2.6.20.1.orig/net/ipv4/tcp_output.c |
| +++ linux-2.6.20.1/net/ipv4/tcp_output.c |
| @@ -481,7 +481,7 @@ static int tcp_transmit_skb(struct sock |
| /* RFC1323: The window in SYN & SYN/ACK segments |
| * is never scaled. |
| */ |
| - th->window = htons(tp->rcv_wnd); |
| + th->window = htons(min(tp->rcv_wnd, 65535U)); |
| } else { |
| th->window = htons(tcp_select_window(sk)); |
| } |
| @@ -2160,7 +2160,7 @@ struct sk_buff * tcp_make_synack(struct |
| } |
| |
| /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ |
| - th->window = htons(req->rcv_wnd); |
| + th->window = htons(min(req->rcv_wnd, 65535U)); |
| |
| TCP_SKB_CB(skb)->when = tcp_time_stamp; |
| tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, |