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

Commit ea2bc483 authored by Tsutomu Fujii's avatar Tsutomu Fujii Committed by David S. Miller
Browse files

[SCTP]: Fix assertion (!atomic_read(&sk->sk_rmem_alloc)) failed message



In current implementation, LKSCTP does receive buffer accounting for
data in sctp_receive_queue and pd_lobby. However, LKSCTP don't do
accounting for data in frag_list when data is fragmented. In addition,
LKSCTP doesn't do accounting for data in reasm and lobby queue in
structure sctp_ulpq.
When there are date in these queue, assertion failed message is printed
in inet_sock_destruct because sk_rmem_alloc of oldsk does not become 0
when socket is destroyed.

Signed-off-by: default avatarTsutomu Fujii <t-fujii@nb.jp.nec.com>
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c2ecba71
Loading
Loading
Loading
Loading
+44 −4
Original line number Diff line number Diff line
@@ -5638,6 +5638,36 @@ void sctp_wait_for_close(struct sock *sk, long timeout)
	finish_wait(sk->sk_sleep, &wait);
}

static void sctp_sock_rfree_frag(struct sk_buff *skb)
{
	struct sk_buff *frag;

	if (!skb->data_len)
		goto done;

	/* Don't forget the fragments. */
	for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
		sctp_sock_rfree_frag(frag);

done:
	sctp_sock_rfree(skb);
}

static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
{
	struct sk_buff *frag;

	if (!skb->data_len)
		goto done;

	/* Don't forget the fragments. */
	for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
		sctp_skb_set_owner_r_frag(frag, sk);

done:
	sctp_skb_set_owner_r(skb, sk);
}

/* Populate the fields of the newsk from the oldsk and migrate the assoc
 * and its messages to the newsk.
 */
@@ -5692,10 +5722,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
	sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
		event = sctp_skb2event(skb);
		if (event->asoc == assoc) {
			sctp_sock_rfree(skb);
			sctp_sock_rfree_frag(skb);
			__skb_unlink(skb, &oldsk->sk_receive_queue);
			__skb_queue_tail(&newsk->sk_receive_queue, skb);
			sctp_skb_set_owner_r(skb, newsk);
			sctp_skb_set_owner_r_frag(skb, newsk);
		}
	}

@@ -5723,10 +5753,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
			event = sctp_skb2event(skb);
			if (event->asoc == assoc) {
				sctp_sock_rfree(skb);
				sctp_sock_rfree_frag(skb);
				__skb_unlink(skb, &oldsp->pd_lobby);
				__skb_queue_tail(queue, skb);
				sctp_skb_set_owner_r(skb, newsk);
				sctp_skb_set_owner_r_frag(skb, newsk);
			}
		}

@@ -5738,6 +5768,16 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,

	}

	sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) {
		sctp_sock_rfree_frag(skb);
		sctp_skb_set_owner_r_frag(skb, newsk);
	}

	sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) {
		sctp_sock_rfree_frag(skb);
		sctp_skb_set_owner_r_frag(skb, newsk);
	}

	/* Set the type of socket to indicate that it is peeled off from the
	 * original UDP-style socket or created with the accept() call on a
	 * TCP-style socket..