Commit 443fac9f authored by Florian Westphal's avatar Florian Westphal Committed by Greg Kroah-Hartman

secure_seq: downgrade to per-host timestamp offsets

[ Upstream commit 28ee1b74 ]

Unfortunately too many devices (not under our control) use tcp_tw_recycle=1,
which depends on timestamps being identical of the same saddr.

Although tcp_tw_recycle got removed in net-next we can't make
such end hosts disappear so downgrade to per-host timestamp offsets.

4.10 note: original patch uses siphash (added in 4.11), since
ts_off is only used to obscure uptime (and doesn't use same secret
as isn generator) this uses jhash instead.

Cc: Soheil Hassas Yeganeh <soheil@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Reported-by: default avatarYvan Vanrossomme <yvan@vanrossomme.net>
Fixes: 95a22cae ("tcp: randomize tcp timestamp offsets for each connection")
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a35c1467
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4) #define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
static u32 ts_secret[2];
static __always_inline void net_secret_init(void) static __always_inline void net_secret_init(void)
{ {
net_get_random_once(ts_secret, sizeof(ts_secret));
net_get_random_once(net_secret, sizeof(net_secret)); net_get_random_once(net_secret, sizeof(net_secret));
} }
#endif #endif
...@@ -41,6 +43,21 @@ static u32 seq_scale(u32 seq) ...@@ -41,6 +43,21 @@ static u32 seq_scale(u32 seq)
#endif #endif
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr)
{
u32 hash[4 + 4 + 1];
if (sysctl_tcp_timestamps != 1)
return 0;
memcpy(hash, saddr, 16);
memcpy(hash + 4, daddr, 16);
hash[8] = ts_secret[0];
return jhash2(hash, ARRAY_SIZE(hash), ts_secret[1]);
}
u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
__be16 sport, __be16 dport, u32 *tsoff) __be16 sport, __be16 dport, u32 *tsoff)
{ {
...@@ -59,7 +76,7 @@ u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, ...@@ -59,7 +76,7 @@ u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
md5_transform(hash, secret); md5_transform(hash, secret);
*tsoff = sysctl_tcp_timestamps == 1 ? hash[1] : 0; *tsoff = secure_tcpv6_ts_off(saddr, daddr);
return seq_scale(hash[0]); return seq_scale(hash[0]);
} }
EXPORT_SYMBOL(secure_tcpv6_sequence_number); EXPORT_SYMBOL(secure_tcpv6_sequence_number);
...@@ -87,6 +104,14 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); ...@@ -87,6 +104,14 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#endif #endif
#ifdef CONFIG_INET #ifdef CONFIG_INET
static u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr)
{
if (sysctl_tcp_timestamps != 1)
return 0;
return jhash_3words((__force u32)saddr, (__force u32)daddr,
ts_secret[0], ts_secret[1]);
}
u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport, u32 *tsoff) __be16 sport, __be16 dport, u32 *tsoff)
...@@ -101,7 +126,7 @@ u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, ...@@ -101,7 +126,7 @@ u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
md5_transform(hash, net_secret); md5_transform(hash, net_secret);
*tsoff = sysctl_tcp_timestamps == 1 ? hash[1] : 0; *tsoff = secure_tcp_ts_off(saddr, daddr);
return seq_scale(hash[0]); return seq_scale(hash[0]);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment