diff options
Diffstat (limited to 'net/sctp/input.c')
-rw-r--r-- | net/sctp/input.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c index ca6b022b1df2..a49fa80b57b9 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include <net/sctp/sctp.h> | 61 | #include <net/sctp/sctp.h> |
62 | #include <net/sctp/sm.h> | 62 | #include <net/sctp/sm.h> |
63 | #include <net/sctp/checksum.h> | 63 | #include <net/sctp/checksum.h> |
64 | #include <net/net_namespace.h> | ||
64 | 65 | ||
65 | /* Forward declarations for internal helpers. */ | 66 | /* Forward declarations for internal helpers. */ |
66 | static int sctp_rcv_ootb(struct sk_buff *); | 67 | static int sctp_rcv_ootb(struct sk_buff *); |
@@ -82,8 +83,8 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb) | |||
82 | { | 83 | { |
83 | struct sk_buff *list = skb_shinfo(skb)->frag_list; | 84 | struct sk_buff *list = skb_shinfo(skb)->frag_list; |
84 | struct sctphdr *sh = sctp_hdr(skb); | 85 | struct sctphdr *sh = sctp_hdr(skb); |
85 | __u32 cmp = ntohl(sh->checksum); | 86 | __be32 cmp = sh->checksum; |
86 | __u32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); | 87 | __be32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); |
87 | 88 | ||
88 | for (; list; list = list->next) | 89 | for (; list; list = list->next) |
89 | val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), | 90 | val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), |
@@ -430,6 +431,9 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
430 | struct sock *sk = NULL; | 431 | struct sock *sk = NULL; |
431 | struct sctp_association *asoc; | 432 | struct sctp_association *asoc; |
432 | struct sctp_transport *transport = NULL; | 433 | struct sctp_transport *transport = NULL; |
434 | struct sctp_init_chunk *chunkhdr; | ||
435 | __u32 vtag = ntohl(sctphdr->vtag); | ||
436 | int len = skb->len - ((void *)sctphdr - (void *)skb->data); | ||
433 | 437 | ||
434 | *app = NULL; *tpp = NULL; | 438 | *app = NULL; *tpp = NULL; |
435 | 439 | ||
@@ -451,8 +455,28 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
451 | 455 | ||
452 | sk = asoc->base.sk; | 456 | sk = asoc->base.sk; |
453 | 457 | ||
454 | if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) { | 458 | /* RFC 4960, Appendix C. ICMP Handling |
455 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 459 | * |
460 | * ICMP6) An implementation MUST validate that the Verification Tag | ||
461 | * contained in the ICMP message matches the Verification Tag of | ||
462 | * the peer. If the Verification Tag is not 0 and does NOT | ||
463 | * match, discard the ICMP message. If it is 0 and the ICMP | ||
464 | * message contains enough bytes to verify that the chunk type is | ||
465 | * an INIT chunk and that the Initiate Tag matches the tag of the | ||
466 | * peer, continue with ICMP7. If the ICMP message is too short | ||
467 | * or the chunk type or the Initiate Tag does not match, silently | ||
468 | * discard the packet. | ||
469 | */ | ||
470 | if (vtag == 0) { | ||
471 | chunkhdr = (struct sctp_init_chunk *)((void *)sctphdr | ||
472 | + sizeof(struct sctphdr)); | ||
473 | if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t) | ||
474 | + sizeof(__be32) || | ||
475 | chunkhdr->chunk_hdr.type != SCTP_CID_INIT || | ||
476 | ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) { | ||
477 | goto out; | ||
478 | } | ||
479 | } else if (vtag != asoc->c.peer_vtag) { | ||
456 | goto out; | 480 | goto out; |
457 | } | 481 | } |
458 | 482 | ||
@@ -462,7 +486,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
462 | * servers this needs to be solved differently. | 486 | * servers this needs to be solved differently. |
463 | */ | 487 | */ |
464 | if (sock_owned_by_user(sk)) | 488 | if (sock_owned_by_user(sk)) |
465 | NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS); | 489 | NET_INC_STATS_BH(&init_net, LINUX_MIB_LOCKDROPPEDICMPS); |
466 | 490 | ||
467 | *app = asoc; | 491 | *app = asoc; |
468 | *tpp = transport; | 492 | *tpp = transport; |
@@ -511,7 +535,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
511 | int err; | 535 | int err; |
512 | 536 | ||
513 | if (skb->len < ihlen + 8) { | 537 | if (skb->len < ihlen + 8) { |
514 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 538 | ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); |
515 | return; | 539 | return; |
516 | } | 540 | } |
517 | 541 | ||
@@ -525,7 +549,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
525 | skb->network_header = saveip; | 549 | skb->network_header = saveip; |
526 | skb->transport_header = savesctp; | 550 | skb->transport_header = savesctp; |
527 | if (!sk) { | 551 | if (!sk) { |
528 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 552 | ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); |
529 | return; | 553 | return; |
530 | } | 554 | } |
531 | /* Warning: The sock lock is held. Remember to call | 555 | /* Warning: The sock lock is held. Remember to call |