]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
calipso: Add validation of CALIPSO option.
authorHuw Davies <huw@codeweavers.com>
Mon, 27 Jun 2016 19:06:17 +0000 (15:06 -0400)
committerPaul Moore <paul@paul-moore.com>
Mon, 27 Jun 2016 19:06:17 +0000 (15:06 -0400)
Lengths, checksum and the DOI are checked.  Checking of the
level and categories are left for the socket layer.

CRC validation is performed in the calipso module to avoid
unconditionally linking crc_ccitt() into ipv6.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
include/net/calipso.h
net/ipv6/calipso.c
net/ipv6/exthdrs.c

index 38dbb47071503ac2052e893fff5909b9474d7254..85404e2375d8b9fa5a6e75f7787e23faf1a21f15 100644 (file)
@@ -65,6 +65,7 @@ struct calipso_doi {
 #ifdef CONFIG_NETLABEL
 int __init calipso_init(void);
 void calipso_exit(void);
+bool calipso_validate(const struct sk_buff *skb, const unsigned char *option);
 #else
 static inline int __init calipso_init(void)
 {
@@ -74,6 +75,11 @@ static inline int __init calipso_init(void)
 static inline void calipso_exit(void)
 {
 }
+static inline bool calipso_validate(const struct sk_buff *skb,
+                                   const unsigned char *option)
+{
+       return true;
+}
 #endif /* CONFIG_NETLABEL */
 
 #endif /* _CALIPSO_H */
index fa371a8827cf5100e109e1cb96db8fef68fe0b9c..ea80450efe564a3ea36049ef83d9e0b6222eb9fe 100644 (file)
@@ -320,6 +320,47 @@ static int calipso_doi_walk(u32 *skip_cnt,
        return ret_val;
 }
 
+/**
+ * calipso_validate - Validate a CALIPSO option
+ * @skb: the packet
+ * @option: the start of the option
+ *
+ * Description:
+ * This routine is called to validate a CALIPSO option.
+ * If the option is valid then %true is returned, otherwise
+ * %false is returned.
+ *
+ * The caller should have already checked that the length of the
+ * option (including the TLV header) is >= 10 and that the catmap
+ * length is consistent with the option length.
+ *
+ * We leave checks on the level and categories to the socket layer.
+ */
+bool calipso_validate(const struct sk_buff *skb, const unsigned char *option)
+{
+       struct calipso_doi *doi_def;
+       bool ret_val;
+       u16 crc, len = option[1] + 2;
+       static const u8 zero[2];
+
+       /* The original CRC runs over the option including the TLV header
+        * with the CRC-16 field (at offset 8) zeroed out. */
+       crc = crc_ccitt(0xffff, option, 8);
+       crc = crc_ccitt(crc, zero, sizeof(zero));
+       if (len > 10)
+               crc = crc_ccitt(crc, option + 10, len - 10);
+       crc = ~crc;
+       if (option[8] != (crc & 0xff) || option[9] != ((crc >> 8) & 0xff))
+               return false;
+
+       rcu_read_lock();
+       doi_def = calipso_doi_search(get_unaligned_be32(option + 2));
+       ret_val = !!doi_def;
+       rcu_read_unlock();
+
+       return ret_val;
+}
+
 /**
  * calipso_map_cat_hton - Perform a category mapping from host to network
  * @doi_def: the DOI definition
index d5fd3e799f86a8e2e51bc132f109f17cbc7f733e..0f69cab39986ef62e15baaf82a9a5df9b3e26d5a 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/ndisc.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
+#include <net/calipso.h>
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
 #include <net/xfrm.h>
 #endif
@@ -603,6 +604,28 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
        return false;
 }
 
+/* CALIPSO RFC 5570 */
+
+static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
+{
+       const unsigned char *nh = skb_network_header(skb);
+
+       if (nh[optoff + 1] < 8)
+               goto drop;
+
+       if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1])
+               goto drop;
+
+       if (!calipso_validate(skb, nh + optoff))
+               goto drop;
+
+       return true;
+
+drop:
+       kfree_skb(skb);
+       return false;
+}
+
 static const struct tlvtype_proc tlvprochopopt_lst[] = {
        {
                .type   = IPV6_TLV_ROUTERALERT,
@@ -612,6 +635,10 @@ static const struct tlvtype_proc tlvprochopopt_lst[] = {
                .type   = IPV6_TLV_JUMBO,
                .func   = ipv6_hop_jumbo,
        },
+       {
+               .type   = IPV6_TLV_CALIPSO,
+               .func   = ipv6_hop_calipso,
+       },
        { -1, }
 };