diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2005-07-18 16:44:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-07-18 16:44:10 -0400 |
commit | d1ad1ff299dd908d07c5e5f27f88bbdb235eb7a5 (patch) | |
tree | 03f66679f4a153ec06fde913907f392503f4b5e5 | |
parent | ee71a29eb5e341fe977c5ad7a43782c29bd9cb9e (diff) |
[SCTP]: Fix potential null pointer dereference while handling an icmp error
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/sctp/sctp.h | 7 | ||||
-rw-r--r-- | net/sctp/input.c | 45 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 7 |
3 files changed, 17 insertions, 42 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 4a26adfaed71..e1d5ec1c23c0 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h | |||
@@ -167,15 +167,12 @@ void sctp_unhash_established(struct sctp_association *); | |||
167 | void sctp_hash_endpoint(struct sctp_endpoint *); | 167 | void sctp_hash_endpoint(struct sctp_endpoint *); |
168 | void sctp_unhash_endpoint(struct sctp_endpoint *); | 168 | void sctp_unhash_endpoint(struct sctp_endpoint *); |
169 | struct sock *sctp_err_lookup(int family, struct sk_buff *, | 169 | struct sock *sctp_err_lookup(int family, struct sk_buff *, |
170 | struct sctphdr *, struct sctp_endpoint **, | 170 | struct sctphdr *, struct sctp_association **, |
171 | struct sctp_association **, | ||
172 | struct sctp_transport **); | 171 | struct sctp_transport **); |
173 | void sctp_err_finish(struct sock *, struct sctp_endpoint *, | 172 | void sctp_err_finish(struct sock *, struct sctp_association *); |
174 | struct sctp_association *); | ||
175 | void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, | 173 | void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, |
176 | struct sctp_transport *t, __u32 pmtu); | 174 | struct sctp_transport *t, __u32 pmtu); |
177 | void sctp_icmp_proto_unreachable(struct sock *sk, | 175 | void sctp_icmp_proto_unreachable(struct sock *sk, |
178 | struct sctp_endpoint *ep, | ||
179 | struct sctp_association *asoc, | 176 | struct sctp_association *asoc, |
180 | struct sctp_transport *t); | 177 | struct sctp_transport *t); |
181 | 178 | ||
diff --git a/net/sctp/input.c b/net/sctp/input.c index 5e085e041a6e..742be9171b7d 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -351,7 +351,6 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, | |||
351 | * | 351 | * |
352 | */ | 352 | */ |
353 | void sctp_icmp_proto_unreachable(struct sock *sk, | 353 | void sctp_icmp_proto_unreachable(struct sock *sk, |
354 | struct sctp_endpoint *ep, | ||
355 | struct sctp_association *asoc, | 354 | struct sctp_association *asoc, |
356 | struct sctp_transport *t) | 355 | struct sctp_transport *t) |
357 | { | 356 | { |
@@ -367,7 +366,6 @@ void sctp_icmp_proto_unreachable(struct sock *sk, | |||
367 | /* Common lookup code for icmp/icmpv6 error handler. */ | 366 | /* Common lookup code for icmp/icmpv6 error handler. */ |
368 | struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | 367 | struct sock *sctp_err_lookup(int family, struct sk_buff *skb, |
369 | struct sctphdr *sctphdr, | 368 | struct sctphdr *sctphdr, |
370 | struct sctp_endpoint **epp, | ||
371 | struct sctp_association **app, | 369 | struct sctp_association **app, |
372 | struct sctp_transport **tpp) | 370 | struct sctp_transport **tpp) |
373 | { | 371 | { |
@@ -375,11 +373,10 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
375 | union sctp_addr daddr; | 373 | union sctp_addr daddr; |
376 | struct sctp_af *af; | 374 | struct sctp_af *af; |
377 | struct sock *sk = NULL; | 375 | struct sock *sk = NULL; |
378 | struct sctp_endpoint *ep = NULL; | ||
379 | struct sctp_association *asoc = NULL; | 376 | struct sctp_association *asoc = NULL; |
380 | struct sctp_transport *transport = NULL; | 377 | struct sctp_transport *transport = NULL; |
381 | 378 | ||
382 | *app = NULL; *epp = NULL; *tpp = NULL; | 379 | *app = NULL; *tpp = NULL; |
383 | 380 | ||
384 | af = sctp_get_af_specific(family); | 381 | af = sctp_get_af_specific(family); |
385 | if (unlikely(!af)) { | 382 | if (unlikely(!af)) { |
@@ -394,26 +391,15 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
394 | * packet. | 391 | * packet. |
395 | */ | 392 | */ |
396 | asoc = __sctp_lookup_association(&saddr, &daddr, &transport); | 393 | asoc = __sctp_lookup_association(&saddr, &daddr, &transport); |
397 | if (!asoc) { | 394 | if (!asoc) |
398 | /* If there is no matching association, see if it matches any | 395 | return NULL; |
399 | * endpoint. This may happen for an ICMP error generated in | ||
400 | * response to an INIT_ACK. | ||
401 | */ | ||
402 | ep = __sctp_rcv_lookup_endpoint(&daddr); | ||
403 | if (!ep) { | ||
404 | return NULL; | ||
405 | } | ||
406 | } | ||
407 | 396 | ||
408 | if (asoc) { | 397 | sk = asoc->base.sk; |
409 | sk = asoc->base.sk; | ||
410 | 398 | ||
411 | if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) { | 399 | if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) { |
412 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 400 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); |
413 | goto out; | 401 | goto out; |
414 | } | 402 | } |
415 | } else | ||
416 | sk = ep->base.sk; | ||
417 | 403 | ||
418 | sctp_bh_lock_sock(sk); | 404 | sctp_bh_lock_sock(sk); |
419 | 405 | ||
@@ -423,7 +409,6 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
423 | if (sock_owned_by_user(sk)) | 409 | if (sock_owned_by_user(sk)) |
424 | NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); | 410 | NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); |
425 | 411 | ||
426 | *epp = ep; | ||
427 | *app = asoc; | 412 | *app = asoc; |
428 | *tpp = transport; | 413 | *tpp = transport; |
429 | return sk; | 414 | return sk; |
@@ -432,21 +417,16 @@ out: | |||
432 | sock_put(sk); | 417 | sock_put(sk); |
433 | if (asoc) | 418 | if (asoc) |
434 | sctp_association_put(asoc); | 419 | sctp_association_put(asoc); |
435 | if (ep) | ||
436 | sctp_endpoint_put(ep); | ||
437 | return NULL; | 420 | return NULL; |
438 | } | 421 | } |
439 | 422 | ||
440 | /* Common cleanup code for icmp/icmpv6 error handler. */ | 423 | /* Common cleanup code for icmp/icmpv6 error handler. */ |
441 | void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, | 424 | void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) |
442 | struct sctp_association *asoc) | ||
443 | { | 425 | { |
444 | sctp_bh_unlock_sock(sk); | 426 | sctp_bh_unlock_sock(sk); |
445 | sock_put(sk); | 427 | sock_put(sk); |
446 | if (asoc) | 428 | if (asoc) |
447 | sctp_association_put(asoc); | 429 | sctp_association_put(asoc); |
448 | if (ep) | ||
449 | sctp_endpoint_put(ep); | ||
450 | } | 430 | } |
451 | 431 | ||
452 | /* | 432 | /* |
@@ -471,7 +451,6 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
471 | int type = skb->h.icmph->type; | 451 | int type = skb->h.icmph->type; |
472 | int code = skb->h.icmph->code; | 452 | int code = skb->h.icmph->code; |
473 | struct sock *sk; | 453 | struct sock *sk; |
474 | struct sctp_endpoint *ep; | ||
475 | struct sctp_association *asoc; | 454 | struct sctp_association *asoc; |
476 | struct sctp_transport *transport; | 455 | struct sctp_transport *transport; |
477 | struct inet_sock *inet; | 456 | struct inet_sock *inet; |
@@ -488,7 +467,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
488 | savesctp = skb->h.raw; | 467 | savesctp = skb->h.raw; |
489 | skb->nh.iph = iph; | 468 | skb->nh.iph = iph; |
490 | skb->h.raw = (char *)sh; | 469 | skb->h.raw = (char *)sh; |
491 | sk = sctp_err_lookup(AF_INET, skb, sh, &ep, &asoc, &transport); | 470 | sk = sctp_err_lookup(AF_INET, skb, sh, &asoc, &transport); |
492 | /* Put back, the original pointers. */ | 471 | /* Put back, the original pointers. */ |
493 | skb->nh.raw = saveip; | 472 | skb->nh.raw = saveip; |
494 | skb->h.raw = savesctp; | 473 | skb->h.raw = savesctp; |
@@ -515,7 +494,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
515 | } | 494 | } |
516 | else { | 495 | else { |
517 | if (ICMP_PROT_UNREACH == code) { | 496 | if (ICMP_PROT_UNREACH == code) { |
518 | sctp_icmp_proto_unreachable(sk, ep, asoc, | 497 | sctp_icmp_proto_unreachable(sk, asoc, |
519 | transport); | 498 | transport); |
520 | goto out_unlock; | 499 | goto out_unlock; |
521 | } | 500 | } |
@@ -544,7 +523,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
544 | } | 523 | } |
545 | 524 | ||
546 | out_unlock: | 525 | out_unlock: |
547 | sctp_err_finish(sk, ep, asoc); | 526 | sctp_err_finish(sk, asoc); |
548 | } | 527 | } |
549 | 528 | ||
550 | /* | 529 | /* |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index c7e42d125b9c..e9b2fd480d61 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -91,7 +91,6 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
91 | struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; | 91 | struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; |
92 | struct sctphdr *sh = (struct sctphdr *)(skb->data + offset); | 92 | struct sctphdr *sh = (struct sctphdr *)(skb->data + offset); |
93 | struct sock *sk; | 93 | struct sock *sk; |
94 | struct sctp_endpoint *ep; | ||
95 | struct sctp_association *asoc; | 94 | struct sctp_association *asoc; |
96 | struct sctp_transport *transport; | 95 | struct sctp_transport *transport; |
97 | struct ipv6_pinfo *np; | 96 | struct ipv6_pinfo *np; |
@@ -105,7 +104,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
105 | savesctp = skb->h.raw; | 104 | savesctp = skb->h.raw; |
106 | skb->nh.ipv6h = iph; | 105 | skb->nh.ipv6h = iph; |
107 | skb->h.raw = (char *)sh; | 106 | skb->h.raw = (char *)sh; |
108 | sk = sctp_err_lookup(AF_INET6, skb, sh, &ep, &asoc, &transport); | 107 | sk = sctp_err_lookup(AF_INET6, skb, sh, &asoc, &transport); |
109 | /* Put back, the original pointers. */ | 108 | /* Put back, the original pointers. */ |
110 | skb->nh.raw = saveip; | 109 | skb->nh.raw = saveip; |
111 | skb->h.raw = savesctp; | 110 | skb->h.raw = savesctp; |
@@ -124,7 +123,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
124 | goto out_unlock; | 123 | goto out_unlock; |
125 | case ICMPV6_PARAMPROB: | 124 | case ICMPV6_PARAMPROB: |
126 | if (ICMPV6_UNK_NEXTHDR == code) { | 125 | if (ICMPV6_UNK_NEXTHDR == code) { |
127 | sctp_icmp_proto_unreachable(sk, ep, asoc, transport); | 126 | sctp_icmp_proto_unreachable(sk, asoc, transport); |
128 | goto out_unlock; | 127 | goto out_unlock; |
129 | } | 128 | } |
130 | break; | 129 | break; |
@@ -142,7 +141,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
142 | } | 141 | } |
143 | 142 | ||
144 | out_unlock: | 143 | out_unlock: |
145 | sctp_err_finish(sk, ep, asoc); | 144 | sctp_err_finish(sk, asoc); |
146 | out: | 145 | out: |
147 | if (likely(idev != NULL)) | 146 | if (likely(idev != NULL)) |
148 | in6_dev_put(idev); | 147 | in6_dev_put(idev); |