| From 75b196e1fbb3ebc5d8804daf5f66ca6340829cb3 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 18 Jul 2021 22:40:13 +0800 |
| Subject: netrom: Decrease sock refcount when sock timers expire |
| |
| From: Nguyen Dinh Phi <phind.uet@gmail.com> |
| |
| [ 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 | 20 +++++++++++--------- |
| 1 file changed, 11 insertions(+), 9 deletions(-) |
| |
| diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c |
| index f0ecaec1ff3d..d1a0b7056743 100644 |
| --- a/net/netrom/nr_timer.c |
| +++ b/net/netrom/nr_timer.c |
| @@ -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); |
| } |
| -- |
| 2.30.2 |
| |