Commit d1ad1ff2 authored by Sridhar Samudrala's avatar Sridhar Samudrala Committed by David S. Miller

[SCTP]: Fix potential null pointer dereference while handling an icmp error

Signed-off-by: default avatarSridhar Samudrala <sri@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ee71a29e
...@@ -167,15 +167,12 @@ void sctp_unhash_established(struct sctp_association *); ...@@ -167,15 +167,12 @@ void sctp_unhash_established(struct sctp_association *);
void sctp_hash_endpoint(struct sctp_endpoint *); void sctp_hash_endpoint(struct sctp_endpoint *);
void sctp_unhash_endpoint(struct sctp_endpoint *); void sctp_unhash_endpoint(struct sctp_endpoint *);
struct sock *sctp_err_lookup(int family, struct sk_buff *, struct sock *sctp_err_lookup(int family, struct sk_buff *,
struct sctphdr *, struct sctp_endpoint **, struct sctphdr *, struct sctp_association **,
struct sctp_association **,
struct sctp_transport **); struct sctp_transport **);
void sctp_err_finish(struct sock *, struct sctp_endpoint *, void sctp_err_finish(struct sock *, struct sctp_association *);
struct sctp_association *);
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_proto_unreachable(struct sock *sk, void sctp_icmp_proto_unreachable(struct sock *sk,
struct sctp_endpoint *ep,
struct sctp_association *asoc, struct sctp_association *asoc,
struct sctp_transport *t); struct sctp_transport *t);
......
...@@ -351,7 +351,6 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, ...@@ -351,7 +351,6 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
* *
*/ */
void sctp_icmp_proto_unreachable(struct sock *sk, void sctp_icmp_proto_unreachable(struct sock *sk,
struct sctp_endpoint *ep,
struct sctp_association *asoc, struct sctp_association *asoc,
struct sctp_transport *t) struct sctp_transport *t)
{ {
...@@ -367,7 +366,6 @@ void sctp_icmp_proto_unreachable(struct sock *sk, ...@@ -367,7 +366,6 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
/* Common lookup code for icmp/icmpv6 error handler. */ /* Common lookup code for icmp/icmpv6 error handler. */
struct sock *sctp_err_lookup(int family, struct sk_buff *skb, struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
struct sctphdr *sctphdr, struct sctphdr *sctphdr,
struct sctp_endpoint **epp,
struct sctp_association **app, struct sctp_association **app,
struct sctp_transport **tpp) struct sctp_transport **tpp)
{ {
...@@ -375,11 +373,10 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, ...@@ -375,11 +373,10 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
union sctp_addr daddr; union sctp_addr daddr;
struct sctp_af *af; struct sctp_af *af;
struct sock *sk = NULL; struct sock *sk = NULL;
struct sctp_endpoint *ep = NULL;
struct sctp_association *asoc = NULL; struct sctp_association *asoc = NULL;
struct sctp_transport *transport = NULL; struct sctp_transport *transport = NULL;
*app = NULL; *epp = NULL; *tpp = NULL; *app = NULL; *tpp = NULL;
af = sctp_get_af_specific(family); af = sctp_get_af_specific(family);
if (unlikely(!af)) { if (unlikely(!af)) {
...@@ -394,26 +391,15 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, ...@@ -394,26 +391,15 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
* packet. * packet.
*/ */
asoc = __sctp_lookup_association(&saddr, &daddr, &transport); asoc = __sctp_lookup_association(&saddr, &daddr, &transport);
if (!asoc) { if (!asoc)
/* If there is no matching association, see if it matches any
* endpoint. This may happen for an ICMP error generated in
* response to an INIT_ACK.
*/
ep = __sctp_rcv_lookup_endpoint(&daddr);
if (!ep) {
return NULL; return NULL;
}
}
if (asoc) {
sk = asoc->base.sk; sk = asoc->base.sk;
if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) { if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) {
ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
goto out; goto out;
} }
} else
sk = ep->base.sk;
sctp_bh_lock_sock(sk); sctp_bh_lock_sock(sk);
...@@ -423,7 +409,6 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, ...@@ -423,7 +409,6 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
*epp = ep;
*app = asoc; *app = asoc;
*tpp = transport; *tpp = transport;
return sk; return sk;
...@@ -432,21 +417,16 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, ...@@ -432,21 +417,16 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
sock_put(sk); sock_put(sk);
if (asoc) if (asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
if (ep)
sctp_endpoint_put(ep);
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_endpoint *ep, void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)
struct sctp_association *asoc)
{ {
sctp_bh_unlock_sock(sk); sctp_bh_unlock_sock(sk);
sock_put(sk); sock_put(sk);
if (asoc) if (asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
if (ep)
sctp_endpoint_put(ep);
} }
/* /*
...@@ -471,7 +451,6 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -471,7 +451,6 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
int type = skb->h.icmph->type; int type = skb->h.icmph->type;
int code = skb->h.icmph->code; int code = skb->h.icmph->code;
struct sock *sk; struct sock *sk;
struct sctp_endpoint *ep;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
struct inet_sock *inet; struct inet_sock *inet;
...@@ -488,7 +467,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -488,7 +467,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
savesctp = skb->h.raw; savesctp = skb->h.raw;
skb->nh.iph = iph; skb->nh.iph = iph;
skb->h.raw = (char *)sh; skb->h.raw = (char *)sh;
sk = sctp_err_lookup(AF_INET, skb, sh, &ep, &asoc, &transport); sk = sctp_err_lookup(AF_INET, skb, sh, &asoc, &transport);
/* Put back, the original pointers. */ /* Put back, the original pointers. */
skb->nh.raw = saveip; skb->nh.raw = saveip;
skb->h.raw = savesctp; skb->h.raw = savesctp;
...@@ -515,7 +494,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -515,7 +494,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
} }
else { else {
if (ICMP_PROT_UNREACH == code) { if (ICMP_PROT_UNREACH == code) {
sctp_icmp_proto_unreachable(sk, ep, asoc, sctp_icmp_proto_unreachable(sk, asoc,
transport); transport);
goto out_unlock; goto out_unlock;
} }
...@@ -544,7 +523,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -544,7 +523,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
} }
out_unlock: out_unlock:
sctp_err_finish(sk, ep, asoc); sctp_err_finish(sk, asoc);
} }
/* /*
......
...@@ -91,7 +91,6 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -91,7 +91,6 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
struct sctphdr *sh = (struct sctphdr *)(skb->data + offset); struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
struct sock *sk; struct sock *sk;
struct sctp_endpoint *ep;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
...@@ -105,7 +104,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -105,7 +104,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
savesctp = skb->h.raw; savesctp = skb->h.raw;
skb->nh.ipv6h = iph; skb->nh.ipv6h = iph;
skb->h.raw = (char *)sh; skb->h.raw = (char *)sh;
sk = sctp_err_lookup(AF_INET6, skb, sh, &ep, &asoc, &transport); sk = sctp_err_lookup(AF_INET6, skb, sh, &asoc, &transport);
/* Put back, the original pointers. */ /* Put back, the original pointers. */
skb->nh.raw = saveip; skb->nh.raw = saveip;
skb->h.raw = savesctp; skb->h.raw = savesctp;
...@@ -124,7 +123,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -124,7 +123,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
goto out_unlock; goto out_unlock;
case ICMPV6_PARAMPROB: case ICMPV6_PARAMPROB:
if (ICMPV6_UNK_NEXTHDR == code) { if (ICMPV6_UNK_NEXTHDR == code) {
sctp_icmp_proto_unreachable(sk, ep, asoc, transport); sctp_icmp_proto_unreachable(sk, asoc, transport);
goto out_unlock; goto out_unlock;
} }
break; break;
...@@ -142,7 +141,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -142,7 +141,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} }
out_unlock: out_unlock:
sctp_err_finish(sk, ep, asoc); sctp_err_finish(sk, asoc);
out: out:
if (likely(idev != NULL)) if (likely(idev != NULL))
in6_dev_put(idev); in6_dev_put(idev);
......
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