aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/input.c')
-rw-r--r--net/sctp/input.c38
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. */
66static int sctp_rcv_ootb(struct sk_buff *); 67static 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