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

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
...@@ -152,7 +152,7 @@ void sctp_unhash_endpoint(struct sctp_endpoint *); ...@@ -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 sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
struct sctphdr *, struct sctp_association **, struct sctphdr *, struct sctp_association **,
struct sctp_transport **); 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 *, void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
struct sctp_transport *t, __u32 pmtu); struct sctp_transport *t, __u32 pmtu);
void sctp_icmp_redirect(struct sock *, struct sctp_transport *, void sctp_icmp_redirect(struct sock *, struct sctp_transport *,
......
...@@ -181,9 +181,10 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -181,9 +181,10 @@ int sctp_rcv(struct sk_buff *skb)
* bound to another interface, via SO_BINDTODEVICE, treat it as OOTB * 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 (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) {
if (asoc) { if (transport) {
sctp_association_put(asoc); sctp_transport_put(transport);
asoc = NULL; asoc = NULL;
transport = NULL;
} else { } else {
sctp_endpoint_put(ep); sctp_endpoint_put(ep);
ep = NULL; ep = NULL;
...@@ -269,8 +270,8 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -269,8 +270,8 @@ int sctp_rcv(struct sk_buff *skb)
bh_unlock_sock(sk); bh_unlock_sock(sk);
/* Release the asoc/ep ref we took in the lookup calls. */ /* Release the asoc/ep ref we took in the lookup calls. */
if (asoc) if (transport)
sctp_association_put(asoc); sctp_transport_put(transport);
else else
sctp_endpoint_put(ep); sctp_endpoint_put(ep);
...@@ -283,8 +284,8 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -283,8 +284,8 @@ int sctp_rcv(struct sk_buff *skb)
discard_release: discard_release:
/* Release the asoc/ep ref we took in the lookup calls. */ /* Release the asoc/ep ref we took in the lookup calls. */
if (asoc) if (transport)
sctp_association_put(asoc); sctp_transport_put(transport);
else else
sctp_endpoint_put(ep); sctp_endpoint_put(ep);
...@@ -300,6 +301,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -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_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
struct sctp_inq *inqueue = &chunk->rcvr->inqueue; struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
struct sctp_transport *t = chunk->transport;
struct sctp_ep_common *rcvr = NULL; struct sctp_ep_common *rcvr = NULL;
int backloged = 0; int backloged = 0;
...@@ -351,7 +353,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -351,7 +353,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
done: done:
/* Release the refs we took in sctp_add_backlog */ /* Release the refs we took in sctp_add_backlog */
if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) 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) else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
sctp_endpoint_put(sctp_ep(rcvr)); sctp_endpoint_put(sctp_ep(rcvr));
else else
...@@ -363,6 +365,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -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) static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
{ {
struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
struct sctp_transport *t = chunk->transport;
struct sctp_ep_common *rcvr = chunk->rcvr; struct sctp_ep_common *rcvr = chunk->rcvr;
int ret; int ret;
...@@ -373,7 +376,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb) ...@@ -373,7 +376,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
* from us * from us
*/ */
if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) 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) else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
sctp_endpoint_hold(sctp_ep(rcvr)); sctp_endpoint_hold(sctp_ep(rcvr));
else else
...@@ -537,15 +540,15 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb, ...@@ -537,15 +540,15 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
return sk; return sk;
out: out:
sctp_association_put(asoc); sctp_transport_put(transport);
return NULL; return NULL;
} }
/* Common cleanup code for icmp/icmpv6 error handler. */ /* 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); 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) ...@@ -641,7 +644,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
} }
out_unlock: out_unlock:
sctp_err_finish(sk, asoc); sctp_err_finish(sk, transport);
} }
/* /*
...@@ -952,11 +955,8 @@ static struct sctp_association *__sctp_lookup_association( ...@@ -952,11 +955,8 @@ static struct sctp_association *__sctp_lookup_association(
goto out; goto out;
asoc = t->asoc; asoc = t->asoc;
sctp_association_hold(asoc);
*pt = t; *pt = t;
sctp_transport_put(t);
out: out:
return asoc; return asoc;
} }
...@@ -986,7 +986,7 @@ int sctp_has_association(struct net *net, ...@@ -986,7 +986,7 @@ int sctp_has_association(struct net *net,
struct sctp_transport *transport; struct sctp_transport *transport;
if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) { if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) {
sctp_association_put(asoc); sctp_transport_put(transport);
return 1; return 1;
} }
...@@ -1021,7 +1021,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, ...@@ -1021,7 +1021,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,
struct sctphdr *sh = sctp_hdr(skb); struct sctphdr *sh = sctp_hdr(skb);
union sctp_params params; union sctp_params params;
sctp_init_chunk_t *init; sctp_init_chunk_t *init;
struct sctp_transport *transport;
struct sctp_af *af; struct sctp_af *af;
/* /*
...@@ -1052,7 +1051,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, ...@@ -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); 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) if (asoc)
return asoc; return asoc;
} }
......
...@@ -198,7 +198,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -198,7 +198,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} }
out_unlock: out_unlock:
sctp_err_finish(sk, asoc); sctp_err_finish(sk, transport);
out: out:
if (likely(idev != NULL)) if (likely(idev != NULL))
in6_dev_put(idev); in6_dev_put(idev);
......
...@@ -4480,12 +4480,9 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), ...@@ -4480,12 +4480,9 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
if (!transport || !sctp_transport_hold(transport)) if (!transport || !sctp_transport_hold(transport))
goto out; goto out;
sctp_association_hold(transport->asoc);
sctp_transport_put(transport);
rcu_read_unlock(); rcu_read_unlock();
err = cb(transport, p); err = cb(transport, p);
sctp_association_put(transport->asoc); sctp_transport_put(transport);
out: out:
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment