aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuw Davies <huw@codeweavers.com>2016-06-27 15:06:17 -0400
committerPaul Moore <paul@paul-moore.com>2016-06-27 15:06:17 -0400
commit2e532b702834c07f614caf4489feb691e713232a (patch)
tree6214ab300ca11aaa1fe4ff47ee4b551a35794432
parenta04e71f631fa3d2fd2aa0404c11484739d1e9073 (diff)
calipso: Add validation of CALIPSO option.
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>
-rw-r--r--include/net/calipso.h6
-rw-r--r--net/ipv6/calipso.c41
-rw-r--r--net/ipv6/exthdrs.c27
3 files changed, 74 insertions, 0 deletions
diff --git a/include/net/calipso.h b/include/net/calipso.h
index 38dbb4707150..85404e2375d8 100644
--- a/include/net/calipso.h
+++ b/include/net/calipso.h
@@ -65,6 +65,7 @@ struct calipso_doi {
65#ifdef CONFIG_NETLABEL 65#ifdef CONFIG_NETLABEL
66int __init calipso_init(void); 66int __init calipso_init(void);
67void calipso_exit(void); 67void calipso_exit(void);
68bool calipso_validate(const struct sk_buff *skb, const unsigned char *option);
68#else 69#else
69static inline int __init calipso_init(void) 70static inline int __init calipso_init(void)
70{ 71{
@@ -74,6 +75,11 @@ static inline int __init calipso_init(void)
74static inline void calipso_exit(void) 75static inline void calipso_exit(void)
75{ 76{
76} 77}
78static inline bool calipso_validate(const struct sk_buff *skb,
79 const unsigned char *option)
80{
81 return true;
82}
77#endif /* CONFIG_NETLABEL */ 83#endif /* CONFIG_NETLABEL */
78 84
79#endif /* _CALIPSO_H */ 85#endif /* _CALIPSO_H */
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
index fa371a8827cf..ea80450efe56 100644
--- a/net/ipv6/calipso.c
+++ b/net/ipv6/calipso.c
@@ -321,6 +321,47 @@ doi_walk_return:
321} 321}
322 322
323/** 323/**
324 * calipso_validate - Validate a CALIPSO option
325 * @skb: the packet
326 * @option: the start of the option
327 *
328 * Description:
329 * This routine is called to validate a CALIPSO option.
330 * If the option is valid then %true is returned, otherwise
331 * %false is returned.
332 *
333 * The caller should have already checked that the length of the
334 * option (including the TLV header) is >= 10 and that the catmap
335 * length is consistent with the option length.
336 *
337 * We leave checks on the level and categories to the socket layer.
338 */
339bool calipso_validate(const struct sk_buff *skb, const unsigned char *option)
340{
341 struct calipso_doi *doi_def;
342 bool ret_val;
343 u16 crc, len = option[1] + 2;
344 static const u8 zero[2];
345
346 /* The original CRC runs over the option including the TLV header
347 * with the CRC-16 field (at offset 8) zeroed out. */
348 crc = crc_ccitt(0xffff, option, 8);
349 crc = crc_ccitt(crc, zero, sizeof(zero));
350 if (len > 10)
351 crc = crc_ccitt(crc, option + 10, len - 10);
352 crc = ~crc;
353 if (option[8] != (crc & 0xff) || option[9] != ((crc >> 8) & 0xff))
354 return false;
355
356 rcu_read_lock();
357 doi_def = calipso_doi_search(get_unaligned_be32(option + 2));
358 ret_val = !!doi_def;
359 rcu_read_unlock();
360
361 return ret_val;
362}
363
364/**
324 * calipso_map_cat_hton - Perform a category mapping from host to network 365 * calipso_map_cat_hton - Perform a category mapping from host to network
325 * @doi_def: the DOI definition 366 * @doi_def: the DOI definition
326 * @secattr: the security attributes 367 * @secattr: the security attributes
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index d5fd3e799f86..0f69cab39986 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -43,6 +43,7 @@
43#include <net/ndisc.h> 43#include <net/ndisc.h>
44#include <net/ip6_route.h> 44#include <net/ip6_route.h>
45#include <net/addrconf.h> 45#include <net/addrconf.h>
46#include <net/calipso.h>
46#if IS_ENABLED(CONFIG_IPV6_MIP6) 47#if IS_ENABLED(CONFIG_IPV6_MIP6)
47#include <net/xfrm.h> 48#include <net/xfrm.h>
48#endif 49#endif
@@ -603,6 +604,28 @@ drop:
603 return false; 604 return false;
604} 605}
605 606
607/* CALIPSO RFC 5570 */
608
609static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
610{
611 const unsigned char *nh = skb_network_header(skb);
612
613 if (nh[optoff + 1] < 8)
614 goto drop;
615
616 if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1])
617 goto drop;
618
619 if (!calipso_validate(skb, nh + optoff))
620 goto drop;
621
622 return true;
623
624drop:
625 kfree_skb(skb);
626 return false;
627}
628
606static const struct tlvtype_proc tlvprochopopt_lst[] = { 629static const struct tlvtype_proc tlvprochopopt_lst[] = {
607 { 630 {
608 .type = IPV6_TLV_ROUTERALERT, 631 .type = IPV6_TLV_ROUTERALERT,
@@ -612,6 +635,10 @@ static const struct tlvtype_proc tlvprochopopt_lst[] = {
612 .type = IPV6_TLV_JUMBO, 635 .type = IPV6_TLV_JUMBO,
613 .func = ipv6_hop_jumbo, 636 .func = ipv6_hop_jumbo,
614 }, 637 },
638 {
639 .type = IPV6_TLV_CALIPSO,
640 .func = ipv6_hop_calipso,
641 },
615 { -1, } 642 { -1, }
616}; 643};
617 644