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

Commit 1137086f authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sctp-hold-transport-fixes'



Xin Long says:

====================
sctp: a bunch of fixes by holding transport

There are several places where it holds assoc after getting transport by
searching from transport rhashtable, it may cause use-after-free issue.

This patchset is to fix them by holding transport instead.

v1->v2:
  Fix the changelog of patch 2/3
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 87557efc dae399d7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ void sctp_unhash_endpoint(struct sctp_endpoint *);
struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
			     struct sctphdr *, struct sctp_association **,
			     struct sctp_transport **);
void sctp_err_finish(struct sock *, struct sctp_association *);
void sctp_err_finish(struct sock *, struct sctp_transport *);
void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
			   struct sctp_transport *t, __u32 pmtu);
void sctp_icmp_redirect(struct sock *, struct sctp_transport *,
+17 −18
Original line number Diff line number Diff line
@@ -181,9 +181,10 @@ int sctp_rcv(struct sk_buff *skb)
	 * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB
	 */
	if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) {
		if (asoc) {
			sctp_association_put(asoc);
		if (transport) {
			sctp_transport_put(transport);
			asoc = NULL;
			transport = NULL;
		} else {
			sctp_endpoint_put(ep);
			ep = NULL;
@@ -269,8 +270,8 @@ int sctp_rcv(struct sk_buff *skb)
	bh_unlock_sock(sk);

	/* Release the asoc/ep ref we took in the lookup calls. */
	if (asoc)
		sctp_association_put(asoc);
	if (transport)
		sctp_transport_put(transport);
	else
		sctp_endpoint_put(ep);

@@ -283,8 +284,8 @@ int sctp_rcv(struct sk_buff *skb)

discard_release:
	/* Release the asoc/ep ref we took in the lookup calls. */
	if (asoc)
		sctp_association_put(asoc);
	if (transport)
		sctp_transport_put(transport);
	else
		sctp_endpoint_put(ep);

@@ -300,6 +301,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
	struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
	struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
	struct sctp_transport *t = chunk->transport;
	struct sctp_ep_common *rcvr = NULL;
	int backloged = 0;

@@ -351,7 +353,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
done:
	/* Release the refs we took in sctp_add_backlog */
	if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
		sctp_association_put(sctp_assoc(rcvr));
		sctp_transport_put(t);
	else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
		sctp_endpoint_put(sctp_ep(rcvr));
	else
@@ -363,6 +365,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
{
	struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
	struct sctp_transport *t = chunk->transport;
	struct sctp_ep_common *rcvr = chunk->rcvr;
	int ret;

@@ -373,7 +376,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
		 * from us
		 */
		if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
			sctp_association_hold(sctp_assoc(rcvr));
			sctp_transport_hold(t);
		else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
			sctp_endpoint_hold(sctp_ep(rcvr));
		else
@@ -537,15 +540,15 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
	return sk;

out:
	sctp_association_put(asoc);
	sctp_transport_put(transport);
	return NULL;
}

/* Common cleanup code for icmp/icmpv6 error handler. */
void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)
void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
{
	bh_unlock_sock(sk);
	sctp_association_put(asoc);
	sctp_transport_put(t);
}

/*
@@ -641,7 +644,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
	}

out_unlock:
	sctp_err_finish(sk, asoc);
	sctp_err_finish(sk, transport);
}

/*
@@ -952,11 +955,8 @@ static struct sctp_association *__sctp_lookup_association(
		goto out;

	asoc = t->asoc;
	sctp_association_hold(asoc);
	*pt = t;

	sctp_transport_put(t);

out:
	return asoc;
}
@@ -986,7 +986,7 @@ int sctp_has_association(struct net *net,
	struct sctp_transport *transport;

	if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) {
		sctp_association_put(asoc);
		sctp_transport_put(transport);
		return 1;
	}

@@ -1021,7 +1021,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,
	struct sctphdr *sh = sctp_hdr(skb);
	union sctp_params params;
	sctp_init_chunk_t *init;
	struct sctp_transport *transport;
	struct sctp_af *af;

	/*
@@ -1052,7 +1051,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,

		af->from_addr_param(paddr, params.addr, sh->source, 0);

		asoc = __sctp_lookup_association(net, laddr, paddr, &transport);
		asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
		if (asoc)
			return asoc;
	}
+1 −1
Original line number Diff line number Diff line
@@ -198,7 +198,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
	}

out_unlock:
	sctp_err_finish(sk, asoc);
	sctp_err_finish(sk, transport);
out:
	if (likely(idev != NULL))
		in6_dev_put(idev);
+1 −4
Original line number Diff line number Diff line
@@ -4480,12 +4480,9 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
	if (!transport || !sctp_transport_hold(transport))
		goto out;

	sctp_association_hold(transport->asoc);
	sctp_transport_put(transport);

	rcu_read_unlock();
	err = cb(transport, p);
	sctp_association_put(transport->asoc);
	sctp_transport_put(transport);

out:
	return err;