mirror of
https://github.com/S3NEO/android_kernel_samsung_msm8226.git
synced 2024-11-07 03:47:13 +00:00
inet: switch IP ID generator to siphash
commit df453700e8d81b1bdafdf684365ee2b9431fb702 upstream. 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> [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk> CVE-2019-10638 Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org> Change-Id: I607618745f8725e7318ec60e470a77bf0e53df8b
This commit is contained in:
parent
8d0da84afe
commit
e6e21b054b
5 changed files with 45 additions and 32 deletions
|
@ -19,6 +19,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);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define __NETNS_IPV4_H__
|
||||
|
||||
#include <net/inet_frag.h>
|
||||
#include <linux/siphash.h>
|
||||
|
||||
struct ctl_table_header;
|
||||
struct ipv4_devconf;
|
||||
|
@ -68,5 +69,6 @@ struct netns_ipv4 {
|
|||
struct fib_rules_ops *mr_rules_ops;
|
||||
#endif
|
||||
#endif
|
||||
siphash_key_t ip_id_key;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1400,19 +1400,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;
|
||||
static bool hashrnd_initialized = false;
|
||||
u32 hash, id;
|
||||
|
||||
if (unlikely(!hashrnd_initialized)) {
|
||||
hashrnd_initialized = true;
|
||||
get_random_bytes(&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);
|
||||
}
|
||||
|
|
|
@ -604,17 +604,21 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
|||
|
||||
void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr, struct rt6_info *rt)
|
||||
{
|
||||
static u32 ip6_idents_hashrnd __read_mostly;
|
||||
static bool hashrnd_initialized = false;
|
||||
const struct {
|
||||
struct in6_addr dst;
|
||||
struct in6_addr src;
|
||||
} __aligned(SIPHASH_ALIGNMENT) combined = {
|
||||
.dst = rt->rt6i_dst.addr,
|
||||
.src = rt->rt6i_src.addr,
|
||||
};
|
||||
u32 hash, id;
|
||||
|
||||
if (unlikely(!hashrnd_initialized)) {
|
||||
hashrnd_initialized = true;
|
||||
get_random_bytes(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
|
||||
}
|
||||
hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd);
|
||||
hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, 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);
|
||||
|
||||
id = ip_idents_reserve(hash, 1);
|
||||
fhdr->identification = htonl(id);
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
*/
|
||||
void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
|
||||
{
|
||||
static u32 ip6_proxy_idents_hashrnd __read_mostly;
|
||||
static bool hashrnd_initialized = false;
|
||||
struct in6_addr buf[2];
|
||||
struct in6_addr *addrs;
|
||||
u32 hash, id;
|
||||
|
@ -21,19 +19,25 @@ void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
|
|||
skb_network_offset(skb) +
|
||||
offsetof(struct ipv6hdr, saddr),
|
||||
sizeof(buf), buf);
|
||||
if (!addrs)
|
||||
return;
|
||||
if (addrs)
|
||||
{
|
||||
const struct {
|
||||
struct in6_addr dst;
|
||||
struct in6_addr src;
|
||||
} __aligned(SIPHASH_ALIGNMENT) combined = {
|
||||
.dst = addrs[1],
|
||||
.src = addrs[0],
|
||||
};
|
||||
|
||||
if (unlikely(!hashrnd_initialized)) {
|
||||
hashrnd_initialized = true;
|
||||
get_random_bytes(&ip6_proxy_idents_hashrnd,
|
||||
sizeof(ip6_proxy_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 = siphash(&combined, sizeof(combined), &net->ipv4.ip_id_key);
|
||||
|
||||
id = ip_idents_reserve(hash, 1);
|
||||
skb_shinfo(skb)->ip6_frag_id = htonl(id);
|
||||
}
|
||||
hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
|
||||
hash = __ipv6_addr_jhash(&addrs[0], hash);
|
||||
hash ^= net_hash_mix(net);
|
||||
|
||||
id = ip_idents_reserve(hash, 1);
|
||||
skb_shinfo(skb)->ip6_frag_id = htonl(id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
|
||||
|
|
Loading…
Reference in a new issue