|
|
34edd9 |
From 62c423d90d1f8d382a266ce98932607b4684fd1e Mon Sep 17 00:00:00 2001
|
|
|
34edd9 |
From: Willy Tarreau <w@1wt.eu>
|
|
|
34edd9 |
Date: Sat, 29 May 2021 13:07:46 +0200
|
|
|
34edd9 |
Subject: [PATCH] ipv6: use prandom_u32() for ID generation
|
|
|
34edd9 |
Patch-mainline: v5.14-rc1
|
|
|
34edd9 |
Git-commit: 62f20e068ccc50d6ab66fdb72ba90da2b9418c99
|
|
|
34edd9 |
References: CVE-2021-45485 bsc#1194094
|
|
|
34edd9 |
|
|
|
34edd9 |
This is a complement to commit aa6dd211e4b1 ("inet: use bigger hash
|
|
|
34edd9 |
table for IP ID generation"), but focusing on some specific aspects
|
|
|
34edd9 |
of IPv6.
|
|
|
34edd9 |
|
|
|
34edd9 |
Contary to IPv4, IPv6 only uses packet IDs with fragments, and with a
|
|
|
34edd9 |
minimum MTU of 1280, it's much less easy to force a remote peer to
|
|
|
34edd9 |
produce many fragments to explore its ID sequence. In addition packet
|
|
|
34edd9 |
IDs are 32-bit in IPv6, which further complicates their analysis. On
|
|
|
34edd9 |
the other hand, it is often easier to choose among plenty of possible
|
|
|
34edd9 |
source addresses and partially work around the bigger hash table the
|
|
|
34edd9 |
commit above permits, which leaves IPv6 partially exposed to some
|
|
|
34edd9 |
possibilities of remote analysis at the risk of weakening some
|
|
|
34edd9 |
protocols like DNS if some IDs can be predicted with a good enough
|
|
|
34edd9 |
probability.
|
|
|
34edd9 |
|
|
|
34edd9 |
Given the wide range of permitted IDs, the risk of collision is extremely
|
|
|
34edd9 |
low so there's no need to rely on the positive increment algorithm that
|
|
|
34edd9 |
is shared with the IPv4 code via ip_idents_reserve(). We have a fast
|
|
|
34edd9 |
PRNG, so let's simply call prandom_u32() and be done with it.
|
|
|
34edd9 |
|
|
|
34edd9 |
Performance measurements at 10 Gbps couldn't show any difference with
|
|
|
34edd9 |
the previous code, even when using a single core, because due to the
|
|
|
34edd9 |
large fragments, we're limited to only ~930 kpps at 10 Gbps and the cost
|
|
|
34edd9 |
of the random generation is completely offset by other operations and by
|
|
|
34edd9 |
the network transfer time. In addition, this change removes the need to
|
|
|
34edd9 |
update a shared entry in the idents table so it may even end up being
|
|
|
34edd9 |
slightly faster on large scale systems where this matters.
|
|
|
34edd9 |
|
|
|
34edd9 |
The risk of at least one collision here is about 1/80 million among
|
|
|
34edd9 |
10 IDs, 1/850k among 100 IDs, and still only 1/8.5k among 1000 IDs,
|
|
|
34edd9 |
which remains very low compared to IPv4 where all IDs are reused
|
|
|
34edd9 |
every 4 to 80ms on a 10 Gbps flow depending on packet sizes.
|
|
|
34edd9 |
|
|
|
34edd9 |
Reported-by: Amit Klein <aksecurity@gmail.com>
|
|
|
34edd9 |
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
|
34edd9 |
Reviewed-by: Eric Dumazet <edumazet@google.com>
|
|
|
34edd9 |
Link: https://lore.kernel.org/r/20210529110746.6796-1-w@1wt.eu
|
|
|
34edd9 |
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
|
34edd9 |
Signed-off-by: Denis Kirjanov <denis.kirjanov@suse.com>
|
|
|
34edd9 |
---
|
|
|
34edd9 |
net/ipv6/output_core.c | 28 +++++-----------------------
|
|
|
34edd9 |
1 file changed, 5 insertions(+), 23 deletions(-)
|
|
|
34edd9 |
|
|
|
34edd9 |
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
|
|
|
34edd9 |
index af36acc1a644..2880dc7d9a49 100644
|
|
|
34edd9 |
--- a/net/ipv6/output_core.c
|
|
|
34edd9 |
+++ b/net/ipv6/output_core.c
|
|
|
34edd9 |
@@ -15,29 +15,11 @@ static u32 __ipv6_select_ident(struct net *net,
|
|
|
34edd9 |
const struct in6_addr *dst,
|
|
|
34edd9 |
const struct in6_addr *src)
|
|
|
34edd9 |
{
|
|
|
34edd9 |
- const struct {
|
|
|
34edd9 |
- struct in6_addr dst;
|
|
|
34edd9 |
- struct in6_addr src;
|
|
|
34edd9 |
- } __aligned(SIPHASH_ALIGNMENT) combined = {
|
|
|
34edd9 |
- .dst = *dst,
|
|
|
34edd9 |
- .src = *src,
|
|
|
34edd9 |
- };
|
|
|
34edd9 |
- u32 hash, id;
|
|
|
34edd9 |
-
|
|
|
34edd9 |
- /* Note the following code is not safe, but this is okay. */
|
|
|
34edd9 |
- if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key)))
|
|
|
34edd9 |
- get_random_bytes(&net->ipv4.ip_id_key,
|
|
|
34edd9 |
- sizeof(net->ipv4.ip_id_key));
|
|
|
34edd9 |
-
|
|
|
34edd9 |
- hash = siphash(&combined, sizeof(combined), &net->ipv4.ip_id_key);
|
|
|
34edd9 |
-
|
|
|
34edd9 |
- /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
|
|
|
34edd9 |
- * set the hight order instead thus minimizing possible future
|
|
|
34edd9 |
- * collisions.
|
|
|
34edd9 |
- */
|
|
|
34edd9 |
- id = ip_idents_reserve(hash, 1);
|
|
|
34edd9 |
- if (unlikely(!id))
|
|
|
34edd9 |
- id = 1 << 31;
|
|
|
34edd9 |
+ u32 id;
|
|
|
34edd9 |
+
|
|
|
34edd9 |
+ do {
|
|
|
34edd9 |
+ id = prandom_u32();
|
|
|
34edd9 |
+ } while (!id);
|
|
|
34edd9 |
|
|
|
34edd9 |
return id;
|
|
|
34edd9 |
}
|
|
|
34edd9 |
--
|
|
|
34edd9 |
2.16.4
|
|
|
34edd9 |
|