Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Huw Davies and committed by
Paul Moore
2e532b70 a04e71f6

+74
+6
include/net/calipso.h
··· 65 65 #ifdef CONFIG_NETLABEL 66 66 int __init calipso_init(void); 67 67 void calipso_exit(void); 68 + bool calipso_validate(const struct sk_buff *skb, const unsigned char *option); 68 69 #else 69 70 static inline int __init calipso_init(void) 70 71 { ··· 74 73 75 74 static inline void calipso_exit(void) 76 75 { 76 + } 77 + static inline bool calipso_validate(const struct sk_buff *skb, 78 + const unsigned char *option) 79 + { 80 + return true; 77 81 } 78 82 #endif /* CONFIG_NETLABEL */ 79 83
+41
net/ipv6/calipso.c
··· 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 + */ 339 + bool 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 365 * calipso_map_cat_hton - Perform a category mapping from host to network 325 366 * @doi_def: the DOI definition 326 367 * @secattr: the security attributes
+27
net/ipv6/exthdrs.c
··· 43 43 #include <net/ndisc.h> 44 44 #include <net/ip6_route.h> 45 45 #include <net/addrconf.h> 46 + #include <net/calipso.h> 46 47 #if IS_ENABLED(CONFIG_IPV6_MIP6) 47 48 #include <net/xfrm.h> 48 49 #endif ··· 604 603 return false; 605 604 } 606 605 606 + /* CALIPSO RFC 5570 */ 607 + 608 + static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff) 609 + { 610 + const unsigned char *nh = skb_network_header(skb); 611 + 612 + if (nh[optoff + 1] < 8) 613 + goto drop; 614 + 615 + if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1]) 616 + goto drop; 617 + 618 + if (!calipso_validate(skb, nh + optoff)) 619 + goto drop; 620 + 621 + return true; 622 + 623 + drop: 624 + kfree_skb(skb); 625 + return false; 626 + } 627 + 607 628 static const struct tlvtype_proc tlvprochopopt_lst[] = { 608 629 { 609 630 .type = IPV6_TLV_ROUTERALERT, ··· 634 611 { 635 612 .type = IPV6_TLV_JUMBO, 636 613 .func = ipv6_hop_jumbo, 614 + }, 615 + { 616 + .type = IPV6_TLV_CALIPSO, 617 + .func = ipv6_hop_calipso, 637 618 }, 638 619 { -1, } 639 620 };