]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
inet: update the IP ID generation algorithm to higher standards.
authorAmit Klein <aksecurity@gmail.com>
Thu, 18 Apr 2019 21:07:11 +0000 (21:07 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 27 Apr 2019 07:30:29 +0000 (09:30 +0200)
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>
net/ipv4/route.c
net/ipv6/ip6_output.c

index ede610a4abc8ac89231f8c9819b60da3dfe1e2a9..5b2a8d04a8a0dc0a17a4a01dc43ceaca2a8f2c21 100644 (file)
@@ -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);
index 2b69a4b965edf66bf6574792beb2d87874841de1..c3cef2d5c0208f83bc1175d623f5d84ac4ea2454 100644 (file)
@@ -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);