diff options
author | Eric Dumazet <edumazet@google.com> | 2017-03-03 17:08:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-03-07 16:58:33 -0500 |
commit | 02b2faaf0af1d85585f6d6980e286d53612acfc2 (patch) | |
tree | 1d5684fc4dd1f82e2fa7883e8f291674a2d3d8b7 /net/ipv4/tcp_timer.c | |
parent | b73d2da8c724bb26885512e1ba47b91e2a9f48c3 (diff) |
tcp: fix various issues for sockets morphing to listen state
Dmitry Vyukov reported a divide by 0 triggered by syzkaller, exploiting
tcp_disconnect() path that was never really considered and/or used
before syzkaller ;)
I was not able to reproduce the bug, but it seems issues here are the
three possible actions that assumed they would never trigger on a
listener.
1) tcp_write_timer_handler
2) tcp_delack_timer_handler
3) MTU reduction
Only IPv6 MTU reduction was properly testing TCP_CLOSE and TCP_LISTEN
states from tcp_v6_mtu_reduced()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_timer.c')
-rw-r--r-- | net/ipv4/tcp_timer.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 40d893556e67..b2ab411c6d37 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -249,7 +249,8 @@ void tcp_delack_timer_handler(struct sock *sk) | |||
249 | 249 | ||
250 | sk_mem_reclaim_partial(sk); | 250 | sk_mem_reclaim_partial(sk); |
251 | 251 | ||
252 | if (sk->sk_state == TCP_CLOSE || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) | 252 | if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || |
253 | !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) | ||
253 | goto out; | 254 | goto out; |
254 | 255 | ||
255 | if (time_after(icsk->icsk_ack.timeout, jiffies)) { | 256 | if (time_after(icsk->icsk_ack.timeout, jiffies)) { |
@@ -552,7 +553,8 @@ void tcp_write_timer_handler(struct sock *sk) | |||
552 | struct inet_connection_sock *icsk = inet_csk(sk); | 553 | struct inet_connection_sock *icsk = inet_csk(sk); |
553 | int event; | 554 | int event; |
554 | 555 | ||
555 | if (sk->sk_state == TCP_CLOSE || !icsk->icsk_pending) | 556 | if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || |
557 | !icsk->icsk_pending) | ||
556 | goto out; | 558 | goto out; |
557 | 559 | ||
558 | if (time_after(icsk->icsk_timeout, jiffies)) { | 560 | if (time_after(icsk->icsk_timeout, jiffies)) { |