Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25df44e9 authored by Nguyen Dinh Phi's avatar Nguyen Dinh Phi Committed by Greg Kroah-Hartman
Browse files

netrom: Decrease sock refcount when sock timers expire



[ Upstream commit 517a16b1a88bdb6b530f48d5d153478b2552d9a8 ]

Commit 63346650 ("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: default avatarNguyen Dinh Phi <phind.uet@gmail.com>
Reported-by: default avatar <syzbot+10f1194569953b72f1ae@syzkaller.appspotmail.com>
Fixes: 63346650 ("netrom: switch to sock timer API")
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 8d7924ce
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -121,11 +121,9 @@ static void nr_heartbeat_expiry(struct timer_list *t)
		   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;

@@ -146,6 +144,8 @@ static void nr_heartbeat_expiry(struct timer_list *t)

	nr_start_heartbeat(sk);
	bh_unlock_sock(sk);
out:
	sock_put(sk);
}

static void nr_t2timer_expiry(struct timer_list *t)
@@ -159,6 +159,7 @@ static void nr_t2timer_expiry(struct timer_list *t)
		nr_enquiry_response(sk);
	}
	bh_unlock_sock(sk);
	sock_put(sk);
}

static void nr_t4timer_expiry(struct timer_list *t)
@@ -169,6 +170,7 @@ static void nr_t4timer_expiry(struct timer_list *t)
	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(struct timer_list *t)
@@ -197,6 +199,7 @@ static void nr_idletimer_expiry(struct timer_list *t)
		sock_set_flag(sk, SOCK_DEAD);
	}
	bh_unlock_sock(sk);
	sock_put(sk);
}

static void nr_t1timer_expiry(struct timer_list *t)
@@ -209,8 +212,7 @@ static void nr_t1timer_expiry(struct timer_list *t)
	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);
@@ -220,8 +222,7 @@ static void nr_t1timer_expiry(struct timer_list *t)
	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);
@@ -231,8 +232,7 @@ static void nr_t1timer_expiry(struct timer_list *t)
	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);
@@ -241,5 +241,7 @@ static void nr_t1timer_expiry(struct timer_list *t)
	}

	nr_start_t1timer(sk);
out:
	bh_unlock_sock(sk);
	sock_put(sk);
}