]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netrom: Decrease sock refcount when sock timers expire
authorNguyen Dinh Phi <phind.uet@gmail.com>
Sun, 18 Jul 2021 14:40:13 +0000 (22:40 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 28 Jul 2021 07:12:35 +0000 (09:12 +0200)
[ Upstream commit 517a16b1a88bdb6b530f48d5d153478b2552d9a8 ]

Commit 63346650c1a9 ("netrom: switch to sock timer API") switched to use
sock timer API. It replaces mod_timer() by sk_reset_timer(), and
del_timer() by sk_stop_timer().

Function sk_reset_timer() will increase the refcount of sock if it is
called on an inactive timer, hence, in case the timer expires, we need to
decrease the refcount ourselves in the handler, otherwise, the sock
refcount will be unbalanced and the sock will never be freed.

Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com>
Reported-by: syzbot+10f1194569953b72f1ae@syzkaller.appspotmail.com
Fixes: 63346650c1a9 ("netrom: switch to sock timer API")
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/netrom/nr_timer.c

index f0ecaec1ff3dae28571b88f6d6ad9380e66619f4..d1a0b70567432b89b7abe603bfa3ba304c4cbc8a 100644 (file)
@@ -125,11 +125,9 @@ static void nr_heartbeat_expiry(unsigned long param)
                   is accepted() it isn't 'dead' so doesn't get removed. */
                if (sock_flag(sk, SOCK_DESTROY) ||
                    (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
-                       sock_hold(sk);
                        bh_unlock_sock(sk);
                        nr_destroy_socket(sk);
-                       sock_put(sk);
-                       return;
+                       goto out;
                }
                break;
 
@@ -150,6 +148,8 @@ static void nr_heartbeat_expiry(unsigned long param)
 
        nr_start_heartbeat(sk);
        bh_unlock_sock(sk);
+out:
+       sock_put(sk);
 }
 
 static void nr_t2timer_expiry(unsigned long param)
@@ -163,6 +163,7 @@ static void nr_t2timer_expiry(unsigned long param)
                nr_enquiry_response(sk);
        }
        bh_unlock_sock(sk);
+       sock_put(sk);
 }
 
 static void nr_t4timer_expiry(unsigned long param)
@@ -172,6 +173,7 @@ static void nr_t4timer_expiry(unsigned long param)
        bh_lock_sock(sk);
        nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY;
        bh_unlock_sock(sk);
+       sock_put(sk);
 }
 
 static void nr_idletimer_expiry(unsigned long param)
@@ -200,6 +202,7 @@ static void nr_idletimer_expiry(unsigned long param)
                sock_set_flag(sk, SOCK_DEAD);
        }
        bh_unlock_sock(sk);
+       sock_put(sk);
 }
 
 static void nr_t1timer_expiry(unsigned long param)
@@ -212,8 +215,7 @@ static void nr_t1timer_expiry(unsigned long param)
        case NR_STATE_1:
                if (nr->n2count == nr->n2) {
                        nr_disconnect(sk, ETIMEDOUT);
-                       bh_unlock_sock(sk);
-                       return;
+                       goto out;
                } else {
                        nr->n2count++;
                        nr_write_internal(sk, NR_CONNREQ);
@@ -223,8 +225,7 @@ static void nr_t1timer_expiry(unsigned long param)
        case NR_STATE_2:
                if (nr->n2count == nr->n2) {
                        nr_disconnect(sk, ETIMEDOUT);
-                       bh_unlock_sock(sk);
-                       return;
+                       goto out;
                } else {
                        nr->n2count++;
                        nr_write_internal(sk, NR_DISCREQ);
@@ -234,8 +235,7 @@ static void nr_t1timer_expiry(unsigned long param)
        case NR_STATE_3:
                if (nr->n2count == nr->n2) {
                        nr_disconnect(sk, ETIMEDOUT);
-                       bh_unlock_sock(sk);
-                       return;
+                       goto out;
                } else {
                        nr->n2count++;
                        nr_requeue_frames(sk);
@@ -244,5 +244,7 @@ static void nr_t1timer_expiry(unsigned long param)
        }
 
        nr_start_t1timer(sk);
+out:
        bh_unlock_sock(sk);
+       sock_put(sk);
 }