From 24c58d8c208fe6fabb2ab5accf30252b28e42380 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 30 Jul 2019 11:20:15 +0200 Subject: [PATCH] inet: switch IP ID generator to siphash (CVE-2019-10638) --- debian/changelog | 1 + ...et-switch-IP-ID-generator-to-siphash.patch | 162 ++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 164 insertions(+) create mode 100644 debian/patches/bugfix/all/net-switch-IP-ID-generator-to-siphash.patch diff --git a/debian/changelog b/debian/changelog index 53583a9f8..f3f3b389e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Mon, 22 Jul 2019 14:00:00 +0200 diff --git a/debian/patches/bugfix/all/net-switch-IP-ID-generator-to-siphash.patch b/debian/patches/bugfix/all/net-switch-IP-ID-generator-to-siphash.patch new file mode 100644 index 000000000..263786943 --- /dev/null +++ b/debian/patches/bugfix/all/net-switch-IP-ID-generator-to-siphash.patch @@ -0,0 +1,162 @@ +From: Eric Dumazet +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 +Reported-by: Amit Klein +Reported-by: Benny Pinkas +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + + 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 + #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); +-- +cgit 1.2-0.3.lf.el7 + diff --git a/debian/patches/series b/debian/patches/series index 0c4ab8d97..2687b28f0 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -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