From patchwork Fri Aug 2 14:14:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Connor Kuehl X-Patchwork-Id: 1141229 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 460Thk4ds6z9s7T; Sat, 3 Aug 2019 00:15:34 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1htYLC-0004GY-L7; Fri, 02 Aug 2019 14:15:30 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1htYLB-0004GD-F1 for kernel-team@lists.ubuntu.com; Fri, 02 Aug 2019 14:15:29 +0000 Received: from mail-pg1-f200.google.com ([209.85.215.200]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1htYK7-0008Ss-Vp for kernel-team@lists.ubuntu.com; Fri, 02 Aug 2019 14:14:24 +0000 Received: by mail-pg1-f200.google.com with SMTP id m19so33035717pgv.7 for ; Fri, 02 Aug 2019 07:14:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=p+gMJemTRkLLO/0glG7z1gkeLoqOBL9xBQlg6UKzncs=; b=OgodTZ90qtmhScd6CZ0rZK8bt+AtsyQYfFA3gOQJ7cMq0bRwXgymFuaLAnAR0l68yU +yhyanvOzr54tntdzLVzP1s2/fjJ58OAo+i20mhQnNFqEnvb3ZBOWHPscalV92BURRW0 L7Luh8UqlGCz2IJEZDXUeGaK4NCHq0VIyk6ut/HNoqvBjE8hYjQbn/jtfTlzRFsvlmRh jWHXcE5gsN/t2HWXHHp6Q2kHMzN/Tt1A3UbDGhXkBC/QnU/MstzTyX3OOwcuKnHlU1tk 70A7O9QeOGjFDgbmQi6Y9j9zyb8CYlVhtlm/s7kHFha9SyZkJk870GdL5vaWOwGgIcKI mUJg== X-Gm-Message-State: APjAAAXp5n5irvfhsG1Xz8WndIStF8EvO4W8bgUGW/0xlPIZosqrP2VA 7dRjOaqpEXEh7hbIbVz4aHw1/5NNYsbXtyReFBZSitn2F/CSIR6K7uBOZ1p52rewh2vvuhUyOnA 8nDyjpA3TUxLit+xLbIFurD/YBwUUrNZiKhGdCPYj5A== X-Received: by 2002:a63:f304:: with SMTP id l4mr123520081pgh.66.1564755262040; Fri, 02 Aug 2019 07:14:22 -0700 (PDT) X-Google-Smtp-Source: APXvYqxBLabjfiS/sJPFU5o3W2EWI8YzsuBAlWKcReUt98USBnRQDrkngh/Wgb7c5aAqKhT65Wg7qw== X-Received: by 2002:a63:f304:: with SMTP id l4mr123520065pgh.66.1564755261780; Fri, 02 Aug 2019 07:14:21 -0700 (PDT) Received: from localhost.localdomain (c-71-63-131-226.hsd1.or.comcast.net. [71.63.131.226]) by smtp.gmail.com with ESMTPSA id z4sm119887880pfg.166.2019.08.02.07.14.20 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Fri, 02 Aug 2019 07:14:20 -0700 (PDT) From: Connor Kuehl To: kernel-team@lists.ubuntu.com Subject: [SRU][B/D][CVE-2019-10638][PATCH] inet: switch IP ID generator to siphash Date: Fri, 2 Aug 2019 07:14:13 -0700 Message-Id: <20190802141413.3484-5-connor.kuehl@canonical.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190802141413.3484-1-connor.kuehl@canonical.com> References: <20190802141413.3484-1-connor.kuehl@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Eric Dumazet CVE-2019-10638 According to Amit Klein and Benny Pinkas, IP ID generation is too weak and might be used by attackers. Even with recent net_hash_mix() fix (netns: provide pure entropy for net_hash_mix()) having 64bit key and Jenkins hash is risky. It is time to switch to siphash and its 128bit keys. Signed-off-by: Eric Dumazet Reported-by: Amit Klein Reported-by: Benny Pinkas Signed-off-by: David S. Miller (cherry picked from commit df453700e8d81b1bdafdf684365ee2b9431fb702) Signed-off-by: Connor Kuehl --- include/linux/siphash.h | 5 +++++ include/net/netns/ipv4.h | 2 ++ net/ipv4/route.c | 12 +++++++----- net/ipv6/output_core.c | 30 ++++++++++++++++-------------- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/include/linux/siphash.h b/include/linux/siphash.h index fa7a6b9cedbf..bf21591a9e5e 100644 --- a/include/linux/siphash.h +++ b/include/linux/siphash.h @@ -21,6 +21,11 @@ typedef struct { u64 key[2]; } siphash_key_t; +static inline bool siphash_key_is_zero(const siphash_key_t *key) +{ + return !(key->key[0] | key->key[1]); +} + u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key); #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key); diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index c23277562a18..2cd8b47cf0ba 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -9,6 +9,7 @@ #include #include #include +#include struct tcpm_hash_bucket; struct ctl_table_header; @@ -206,5 +207,6 @@ struct netns_ipv4 { unsigned int ipmr_seq; /* protected by rtnl_mutex */ atomic_t rt_genid; + siphash_key_t ip_id_key; }; #endif diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 00dd6c591af0..956290896808 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -517,15 +517,17 @@ EXPORT_SYMBOL(ip_idents_reserve); void __ip_select_ident(struct net *net, struct iphdr *iph, int segs) { - static u32 ip_idents_hashrnd __read_mostly; u32 hash, id; - net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd)); + /* Note the following code is not safe, but this is okay. */ + if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key))) + get_random_bytes(&net->ipv4.ip_id_key, + sizeof(net->ipv4.ip_id_key)); - hash = jhash_3words((__force u32)iph->daddr, + hash = siphash_3u32((__force u32)iph->daddr, (__force u32)iph->saddr, - iph->protocol ^ net_hash_mix(net), - ip_idents_hashrnd); + iph->protocol, + &net->ipv4.ip_id_key); id = ip_idents_reserve(hash, segs); iph->id = htons(id); } diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 4fe7c90962dd..868ae23dbae1 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -10,15 +10,25 @@ #include #include -static u32 __ipv6_select_ident(struct net *net, u32 hashrnd, +static u32 __ipv6_select_ident(struct net *net, const struct in6_addr *dst, const struct in6_addr *src) { + const struct { + struct in6_addr dst; + struct in6_addr src; + } __aligned(SIPHASH_ALIGNMENT) combined = { + .dst = *dst, + .src = *src, + }; u32 hash, id; - hash = __ipv6_addr_jhash(dst, hashrnd); - hash = __ipv6_addr_jhash(src, hash); - hash ^= net_hash_mix(net); + /* Note the following code is not safe, but this is okay. */ + if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key))) + get_random_bytes(&net->ipv4.ip_id_key, + sizeof(net->ipv4.ip_id_key)); + + hash = siphash(&combined, sizeof(combined), &net->ipv4.ip_id_key); /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve, * set the hight order instead thus minimizing possible future @@ -41,7 +51,6 @@ static u32 __ipv6_select_ident(struct net *net, u32 hashrnd, */ __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) { - static u32 ip6_proxy_idents_hashrnd __read_mostly; struct in6_addr buf[2]; struct in6_addr *addrs; u32 id; @@ -53,11 +62,7 @@ __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) if (!addrs) return 0; - net_get_random_once(&ip6_proxy_idents_hashrnd, - sizeof(ip6_proxy_idents_hashrnd)); - - id = __ipv6_select_ident(net, ip6_proxy_idents_hashrnd, - &addrs[1], &addrs[0]); + id = __ipv6_select_ident(net, &addrs[1], &addrs[0]); return htonl(id); } EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); @@ -66,12 +71,9 @@ __be32 ipv6_select_ident(struct net *net, const struct in6_addr *daddr, const struct in6_addr *saddr) { - static u32 ip6_idents_hashrnd __read_mostly; u32 id; - net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); - - id = __ipv6_select_ident(net, ip6_idents_hashrnd, daddr, saddr); + id = __ipv6_select_ident(net, daddr, saddr); return htonl(id); } EXPORT_SYMBOL(ipv6_select_ident);