diff options
author | jtl <jtl@FreeBSD.org> | 2016-05-06 01:26:58 +0000 |
---|---|---|
committer | jtl <jtl@FreeBSD.org> | 2016-05-06 01:26:58 +0000 |
commit | fdef3ab0211b87d886c8a87fe46be53c0642ee0c (patch) | |
tree | 147cfb0105d56f137b7bd090d40693109a5a70dd /sys/netinet/tcp_input.c | |
parent | 5cba75d7c70f66075115953d248d0636c4d4085b (diff) | |
download | FreeBSD-src-fdef3ab0211b87d886c8a87fe46be53c0642ee0c.zip FreeBSD-src-fdef3ab0211b87d886c8a87fe46be53c0642ee0c.tar.gz |
MFC r298408:
Prevent underflows in tp->snd_wnd if the remote side ACKs more than
tp->snd_wnd. This can happen, for example, when the remote side responds
to a window probe by ACKing the one byte it contains.
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 32133ae..435383d 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -2733,6 +2733,9 @@ process_ACK: INP_WLOCK_ASSERT(tp->t_inpcb); acked = BYTES_THIS_ACK(tp, th); + KASSERT(acked >= 0, ("%s: acked unexepectedly negative " + "(tp->snd_una=%u, th->th_ack=%u, tp=%p, m=%p)", __func__, + tp->snd_una, th->th_ack, tp, m)); TCPSTAT_INC(tcps_rcvackpack); TCPSTAT_ADD(tcps_rcvackbyte, acked); @@ -2802,13 +2805,19 @@ process_ACK: SOCKBUF_LOCK(&so->so_snd); if (acked > so->so_snd.sb_cc) { - tp->snd_wnd -= so->so_snd.sb_cc; + if (tp->snd_wnd >= so->so_snd.sb_cc) + tp->snd_wnd -= so->so_snd.sb_cc; + else + tp->snd_wnd = 0; mfree = sbcut_locked(&so->so_snd, (int)so->so_snd.sb_cc); ourfinisacked = 1; } else { mfree = sbcut_locked(&so->so_snd, acked); - tp->snd_wnd -= acked; + if (tp->snd_wnd >= (u_long) acked) + tp->snd_wnd -= acked; + else + tp->snd_wnd = 0; ourfinisacked = 0; } /* NB: sowwakeup_locked() does an implicit unlock. */ |