summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmit Klein <aksecurity@gmail.com>2019-04-18 21:07:11 +0000
committerBen Hutchings <ben@decadent.org.uk>2019-05-11 15:22:47 +0100
commit8b197d3ce585d6777197e0633d71e5af7d98cb35 (patch)
tree213a7351376f24f60ea0f7e73b1bf1fd1924e265
parent725e0dd2d3d036a6bfb170e307ca231228ddddd0 (diff)
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> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-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 4f7c378c841d..13816361fc04 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -487,13 +487,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 e59b30054b0f..bb98cde51476 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -541,12 +541,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);