sctp: Validate Initiate Tag when handling ICMP message
[pandora-kernel.git] / net / sctp / input.c
index d695f71..d354a23 100644 (file)
@@ -1,4 +1,4 @@
-/* SCTP kernel reference Implementation
+/* SCTP kernel implementation
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001-2003 International Business Machines, Corp.
@@ -6,17 +6,17 @@
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
  *
- * This file is part of the SCTP kernel reference Implementation
+ * This file is part of the SCTP kernel implementation
  *
  * These functions handle all input from the IP layer into SCTP.
  *
- * The SCTP reference implementation is free software;
+ * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
  *
- * The SCTP reference implementation is distributed in the hope that it
+ * This SCTP implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -409,7 +409,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
                           struct sctp_association *asoc,
                           struct sctp_transport *t)
 {
-       SCTP_DEBUG_PRINTK("%s\n",  __FUNCTION__);
+       SCTP_DEBUG_PRINTK("%s\n",  __func__);
 
        sctp_do_sm(SCTP_EVENT_T_OTHER,
                   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
@@ -430,6 +430,9 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
        struct sock *sk = NULL;
        struct sctp_association *asoc;
        struct sctp_transport *transport = NULL;
+       struct sctp_init_chunk *chunkhdr;
+       __u32 vtag = ntohl(sctphdr->vtag);
+       int len = skb->len - ((void *)sctphdr - (void *)skb->data);
 
        *app = NULL; *tpp = NULL;
 
@@ -451,8 +454,28 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
 
        sk = asoc->base.sk;
 
-       if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) {
-               ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
+       /* RFC 4960, Appendix C. ICMP Handling
+        *
+        * ICMP6) An implementation MUST validate that the Verification Tag
+        * contained in the ICMP message matches the Verification Tag of
+        * the peer.  If the Verification Tag is not 0 and does NOT
+        * match, discard the ICMP message.  If it is 0 and the ICMP
+        * message contains enough bytes to verify that the chunk type is
+        * an INIT chunk and that the Initiate Tag matches the tag of the
+        * peer, continue with ICMP7.  If the ICMP message is too short
+        * or the chunk type or the Initiate Tag does not match, silently
+        * discard the packet.
+        */
+       if (vtag == 0) {
+               chunkhdr = (struct sctp_init_chunk *)((void *)sctphdr
+                               + sizeof(struct sctphdr));
+               if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t)
+                         + sizeof(__be32) ||
+                   chunkhdr->chunk_hdr.type != SCTP_CID_INIT ||
+                   ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) {
+                       goto out;
+               }
+       } else if (vtag != asoc->c.peer_vtag) {
                goto out;
        }
 
@@ -725,7 +748,6 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l
        }
 
        ep = sctp_sk((sctp_get_ctl_sock()))->ep;
-       epb = &ep->base;
 
 hit:
        sctp_endpoint_hold(ep);
@@ -944,7 +966,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
 static struct sctp_association *__sctp_rcv_asconf_lookup(
                                        sctp_chunkhdr_t *ch,
                                        const union sctp_addr *laddr,
-                                       __be32 peer_port,
+                                       __be16 peer_port,
                                        struct sctp_transport **transportp)
 {
        sctp_addip_chunk_t *asconf = (struct sctp_addip_chunk *)ch;