inet: switch IP ID generator to siphash (CVE-2019-10638)
This commit is contained in:
parent
4962cdb584
commit
24c58d8c20
|
@ -9,6 +9,7 @@ linux (4.19.37-5+deb10u2) UNRELEASED; urgency=medium
|
|||
* scsi: libsas: fix a race condition when smp task timeout (CVE-2018-20836)
|
||||
* Input: gtco - bounds check collection indent level (CVE-2019-13631)
|
||||
* floppy: fix out-of-bounds read in copy_buffer (CVE-2019-14283)
|
||||
* inet: switch IP ID generator to siphash (CVE-2019-10638)
|
||||
|
||||
-- Romain Perier <romain.perier@gmail.com> Mon, 22 Jul 2019 14:00:00 +0200
|
||||
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Wed, 27 Mar 2019 12:40:33 -0700
|
||||
Subject: inet: switch IP ID generator to siphash
|
||||
Origin: https://git.kernel.org/linus/df453700e8d81b1bdafdf684365ee2b9431fb702
|
||||
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-10638
|
||||
|
||||
[ Upstream commit df453700e8d81b1bdafdf684365ee2b9431fb702 ]
|
||||
|
||||
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 <edumazet@google.com>
|
||||
Reported-by: Amit Klein <aksecurity@gmail.com>
|
||||
Reported-by: Benny Pinkas <benny@pinkas.net>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
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 e47503b4e4d1..622db6bc2f02 100644
|
||||
--- a/include/net/netns/ipv4.h
|
||||
+++ b/include/net/netns/ipv4.h
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/uidgid.h>
|
||||
#include <net/inet_frag.h>
|
||||
#include <linux/rcupdate.h>
|
||||
+#include <linux/siphash.h>
|
||||
|
||||
struct tcpm_hash_bucket;
|
||||
struct ctl_table_header;
|
||||
@@ -214,5 +215,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 8bacbcd2db90..40bf19f7ae1a 100644
|
||||
--- a/net/ipv4/route.c
|
||||
+++ b/net/ipv4/route.c
|
||||
@@ -500,15 +500,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 <net/secure_seq.h>
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
-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);
|
||||
--
|
||||
cgit 1.2-0.3.lf.el7
|
||||
|
|
@ -236,6 +236,7 @@ bugfix/all/binder-fix-race-between-munmap-and-direct-reclaim.patch
|
|||
bugfix/all/scsi-libsas-fix-a-race-condition-when-smp-task-timeout.patch
|
||||
bugfix/all/input-gtco-bounds-check-collection-indent-level.patch
|
||||
bugfix/all/floppy-fix-out-of-bounds-read-in-copy_buffer.patch
|
||||
bugfix/all/net-switch-IP-ID-generator-to-siphash.patch
|
||||
|
||||
# Fix exported symbol versions
|
||||
bugfix/all/module-disable-matching-missing-version-crc.patch
|
||||
|
|
Loading…
Reference in New Issue