summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAmit Klein <aksecurity@gmail.com>2019-04-18 21:07:11 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-04-27 09:30:29 +0200
commit55f0fc7a02de8f12757f4937143d8d5091b2e40b (patch)
tree7467819b2e66029109b20eca7bd736867e64a052 /net
parent8620392634e75cd4b08af3c070af87814593125e (diff)
downloadlinux-stable-55f0fc7a02de8f12757f4937143d8d5091b2e40b.tar.gz
linux-stable-55f0fc7a02de8f12757f4937143d8d5091b2e40b.tar.bz2
linux-stable-55f0fc7a02de8f12757f4937143d8d5091b2e40b.zip
inet: update the IP ID generation algorithm to higher standards.
Commit 355b98553789 ("netns: provide pure entropy for net_hash_mix()") makes net_hash_mix() return a true 32 bits of entropy. When used in the IP ID generation algorithm, this has the effect of extending the IP ID generation key from 32 bits to 64 bits. However, net_hash_mix() is only used for IP ID generation starting with kernel version 4.1. Therefore, earlier kernels remain with 32-bit key no matter what the net_hash_mix() return value is. This change addresses the issue by explicitly extending the key to 64 bits for kernels older than 4.1. Signed-off-by: Amit Klein <aksecurity@gmail.com> Cc: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/route.c4
-rw-r--r--net/ipv6/ip6_output.c3
2 files changed, 6 insertions, 1 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index ede610a4abc8..5b2a8d04a8a0 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -488,13 +488,15 @@ EXPORT_SYMBOL(ip_idents_reserve);
void __ip_select_ident(struct iphdr *iph, int segs)
{
static u32 ip_idents_hashrnd __read_mostly;
+ static u32 ip_idents_hashrnd_extra __read_mostly;
u32 hash, id;
net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd));
+ net_get_random_once(&ip_idents_hashrnd_extra, sizeof(ip_idents_hashrnd_extra));
hash = jhash_3words((__force u32)iph->daddr,
(__force u32)iph->saddr,
- iph->protocol,
+ iph->protocol ^ ip_idents_hashrnd_extra,
ip_idents_hashrnd);
id = ip_idents_reserve(hash, segs);
iph->id = htons(id);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 2b69a4b965ed..c3cef2d5c020 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -546,12 +546,15 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
{
static u32 ip6_idents_hashrnd __read_mostly;
+ static u32 ip6_idents_hashrnd_extra __read_mostly;
u32 hash, id;
net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
+ net_get_random_once(&ip6_idents_hashrnd_extra, sizeof(ip6_idents_hashrnd_extra));
hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd);
hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash);
+ hash = jhash_1word(hash, ip6_idents_hashrnd_extra);
id = ip_idents_reserve(hash, 1);
fhdr->identification = htonl(id);