From patchwork Mon Jun 20 13:36:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Huw Davies X-Patchwork-Id: 638027 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3rYD3G5Q5Zz9t0X for ; Tue, 21 Jun 2016 00:37:30 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=codeweavers.com header.i=@codeweavers.com header.b=pyzM6Ihm; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752241AbcFTOhX (ORCPT ); Mon, 20 Jun 2016 10:37:23 -0400 Received: from mail.codeweavers.com ([216.251.189.131]:49821 "EHLO mail.codeweavers.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751781AbcFTOhR (ORCPT ); Mon, 20 Jun 2016 10:37:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=6377696661; h=Message-Id:Date:Subject:Cc:To:From; bh=nrz9Ez/TOAPZTYeny02YeHfUtQkydo6Msmh3bCg3LBc=; b=pyzM6IhmFlEXP6pCuF8yXcv7moKjIjg/oO587HKPL3t2GAFYVht0UoKGYbo9yRb7HsVsoC+yqf6h+9TR8APiLhIP6R9u/f0N9Uj4/99F4H4MzoSfemE9VonQA5au24sDvhPlP8VJDx+uVQN5Jp+Mmij4AAClmOypV9OH+vFlEo4=; Received: from vpn38.vpn.mn.codeweavers.com ([10.69.139.38] helo=merlot.physics.ox.ac.uk) by mail.codeweavers.com with esmtpsa (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from ) id 1bEzO0-00028s-7a; Mon, 20 Jun 2016 08:37:09 -0500 Received: from daviesh by merlot.physics.ox.ac.uk with local (Exim 4.86_2) (envelope-from ) id 1bEzNu-0003M0-BY; Mon, 20 Jun 2016 14:37:02 +0100 From: Huw Davies To: netdev@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@tycho.nsa.gov Cc: Paul Moore Subject: [PATCH v4 17/19] calipso: Add validation of CALIPSO option. Date: Mon, 20 Jun 2016 14:36:57 +0100 Message-Id: <1466429819-12707-18-git-send-email-huw@codeweavers.com> X-Mailer: git-send-email 2.7.4 X-Spam-Score: -4.3 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- include/net/calipso.h | 6 ++++++ net/ipv6/calipso.c | 41 +++++++++++++++++++++++++++++++++++++++++ net/ipv6/exthdrs.c | 27 +++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/include/net/calipso.h b/include/net/calipso.h index 38dbb47..85404e2 100644 --- a/include/net/calipso.h +++ b/include/net/calipso.h @@ -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 */ diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c index fa371a8..ea80450 100644 --- a/net/ipv6/calipso.c +++ b/net/ipv6/calipso.c @@ -321,6 +321,47 @@ doi_walk_return: } /** + * 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 * @secattr: the security attributes diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index d5fd3e7..0f69cab 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -43,6 +43,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_IPV6_MIP6) #include #endif @@ -603,6 +604,28 @@ drop: 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, } };