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

Commit 51359bfc authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sctp-accept-deadlock'



Karl Heiss says:

====================
sctp: Fix SCTP deadlock

These patches fix a deadlock during accept() of an SCTP connection.

The first patch fixes whitespace issues.

The second patch actually fixes the deadlock race.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 43ae93a9 635682a1
Loading
Loading
Loading
Loading
+24 −20
Original line number Original line Diff line number Diff line
@@ -244,12 +244,13 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
	int error;
	int error;
	struct sctp_transport *transport = (struct sctp_transport *) peer;
	struct sctp_transport *transport = (struct sctp_transport *) peer;
	struct sctp_association *asoc = transport->asoc;
	struct sctp_association *asoc = transport->asoc;
	struct net *net = sock_net(asoc->base.sk);
	struct sock *sk = asoc->base.sk;
	struct net *net = sock_net(sk);


	/* Check whether a task is in the sock.  */
	/* Check whether a task is in the sock.  */


	bh_lock_sock(asoc->base.sk);
	bh_lock_sock(sk);
	if (sock_owned_by_user(asoc->base.sk)) {
	if (sock_owned_by_user(sk)) {
		pr_debug("%s: sock is busy\n", __func__);
		pr_debug("%s: sock is busy\n", __func__);


		/* Try again later.  */
		/* Try again later.  */
@@ -272,10 +273,10 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
			   transport, GFP_ATOMIC);
			   transport, GFP_ATOMIC);


	if (error)
	if (error)
		asoc->base.sk->sk_err = -error;
		sk->sk_err = -error;


out_unlock:
out_unlock:
	bh_unlock_sock(asoc->base.sk);
	bh_unlock_sock(sk);
	sctp_transport_put(transport);
	sctp_transport_put(transport);
}
}


@@ -285,11 +286,12 @@ out_unlock:
static void sctp_generate_timeout_event(struct sctp_association *asoc,
static void sctp_generate_timeout_event(struct sctp_association *asoc,
					sctp_event_timeout_t timeout_type)
					sctp_event_timeout_t timeout_type)
{
{
	struct net *net = sock_net(asoc->base.sk);
	struct sock *sk = asoc->base.sk;
	struct net *net = sock_net(sk);
	int error = 0;
	int error = 0;


	bh_lock_sock(asoc->base.sk);
	bh_lock_sock(sk);
	if (sock_owned_by_user(asoc->base.sk)) {
	if (sock_owned_by_user(sk)) {
		pr_debug("%s: sock is busy: timer %d\n", __func__,
		pr_debug("%s: sock is busy: timer %d\n", __func__,
			 timeout_type);
			 timeout_type);


@@ -312,10 +314,10 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
			   (void *)timeout_type, GFP_ATOMIC);
			   (void *)timeout_type, GFP_ATOMIC);


	if (error)
	if (error)
		asoc->base.sk->sk_err = -error;
		sk->sk_err = -error;


out_unlock:
out_unlock:
	bh_unlock_sock(asoc->base.sk);
	bh_unlock_sock(sk);
	sctp_association_put(asoc);
	sctp_association_put(asoc);
}
}


@@ -365,10 +367,11 @@ void sctp_generate_heartbeat_event(unsigned long data)
	int error = 0;
	int error = 0;
	struct sctp_transport *transport = (struct sctp_transport *) data;
	struct sctp_transport *transport = (struct sctp_transport *) data;
	struct sctp_association *asoc = transport->asoc;
	struct sctp_association *asoc = transport->asoc;
	struct net *net = sock_net(asoc->base.sk);
	struct sock *sk = asoc->base.sk;
	struct net *net = sock_net(sk);


	bh_lock_sock(asoc->base.sk);
	bh_lock_sock(sk);
	if (sock_owned_by_user(asoc->base.sk)) {
	if (sock_owned_by_user(sk)) {
		pr_debug("%s: sock is busy\n", __func__);
		pr_debug("%s: sock is busy\n", __func__);


		/* Try again later.  */
		/* Try again later.  */
@@ -389,10 +392,10 @@ void sctp_generate_heartbeat_event(unsigned long data)
			   transport, GFP_ATOMIC);
			   transport, GFP_ATOMIC);


	if (error)
	if (error)
		 asoc->base.sk->sk_err = -error;
		sk->sk_err = -error;


out_unlock:
out_unlock:
	bh_unlock_sock(asoc->base.sk);
	bh_unlock_sock(sk);
	sctp_transport_put(transport);
	sctp_transport_put(transport);
}
}


@@ -403,10 +406,11 @@ void sctp_generate_proto_unreach_event(unsigned long data)
{
{
	struct sctp_transport *transport = (struct sctp_transport *) data;
	struct sctp_transport *transport = (struct sctp_transport *) data;
	struct sctp_association *asoc = transport->asoc;
	struct sctp_association *asoc = transport->asoc;
	struct net *net = sock_net(asoc->base.sk);
	struct sock *sk = asoc->base.sk;
	struct net *net = sock_net(sk);


	bh_lock_sock(asoc->base.sk);
	bh_lock_sock(sk);
	if (sock_owned_by_user(asoc->base.sk)) {
	if (sock_owned_by_user(sk)) {
		pr_debug("%s: sock is busy\n", __func__);
		pr_debug("%s: sock is busy\n", __func__);


		/* Try again later.  */
		/* Try again later.  */
@@ -427,7 +431,7 @@ void sctp_generate_proto_unreach_event(unsigned long data)
		   asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);
		   asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);


out_unlock:
out_unlock:
	bh_unlock_sock(asoc->base.sk);
	bh_unlock_sock(sk);
	sctp_association_put(asoc);
	sctp_association_put(asoc);
}
}