2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-01-08 15:54:02 +03:00
/*
* Copyright ( C ) 2016 Jason A . Donenfeld < Jason @ zx2c4 . com > . All Rights Reserved .
*/
2011-08-04 07:50:44 +04:00
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/cache.h>
# include <linux/random.h>
# include <linux/hrtimer.h>
# include <linux/ktime.h>
# include <linux/string.h>
2013-10-19 23:48:59 +04:00
# include <linux/net.h>
2017-01-08 15:54:02 +03:00
# include <linux/siphash.h>
2011-08-04 07:50:44 +04:00
# include <net/secure_seq.h>
2013-10-06 00:56:59 +04:00
# if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
2017-01-08 15:54:02 +03:00
# include <linux/in6.h>
2016-12-01 13:32:07 +03:00
# include <net/tcp.h>
2011-08-04 07:50:44 +04:00
2021-11-15 20:23:03 +03:00
static siphash_aligned_key_t net_secret ;
static siphash_aligned_key_t ts_secret ;
2013-09-24 17:19:57 +04:00
2013-10-23 10:44:50 +04:00
static __always_inline void net_secret_init ( void )
2011-08-04 07:50:44 +04:00
{
2017-01-08 15:54:02 +03:00
net_get_random_once ( & net_secret , sizeof ( net_secret ) ) ;
2011-08-04 07:50:44 +04:00
}
2017-05-05 16:56:54 +03:00
static __always_inline void ts_secret_init ( void )
{
net_get_random_once ( & ts_secret , sizeof ( ts_secret ) ) ;
}
2013-10-06 00:56:59 +04:00
# endif
2011-08-04 07:50:44 +04:00
2011-12-06 12:04:40 +04:00
# ifdef CONFIG_INET
2011-08-04 07:50:44 +04:00
static u32 seq_scale ( u32 seq )
{
/*
* As close as possible to RFC 793 , which
* suggests using a 250 kHz clock .
* Further reading shows this assumes 2 Mb / s networks .
* For 10 Mb / s Ethernet , a 1 MHz clock is appropriate .
* For 10 Gb / s Ethernet , a 1 GHz clock should be ok , but
* we also need to limit the resolution so that the u32 seq
* overlaps less than one time per MSL ( 2 minutes ) .
* Choosing a clock of 64 ns period is OK . ( period of 274 s )
*/
2014-08-23 05:32:09 +04:00
return seq + ( ktime_get_real_ns ( ) > > 6 ) ;
2011-08-04 07:50:44 +04:00
}
2011-12-06 12:04:40 +04:00
# endif
2011-08-04 07:50:44 +04:00
2011-12-10 13:48:31 +04:00
# if IS_ENABLED(CONFIG_IPV6)
2017-06-07 20:34:39 +03:00
u32 secure_tcpv6_ts_off ( const struct net * net ,
const __be32 * saddr , const __be32 * daddr )
2017-03-24 21:42:37 +03:00
{
const struct {
struct in6_addr saddr ;
struct in6_addr daddr ;
} __aligned ( SIPHASH_ALIGNMENT ) combined = {
. saddr = * ( struct in6_addr * ) saddr ,
. daddr = * ( struct in6_addr * ) daddr ,
} ;
2017-06-07 20:34:39 +03:00
if ( net - > ipv4 . sysctl_tcp_timestamps ! = 1 )
2017-03-24 21:42:37 +03:00
return 0 ;
2017-05-05 16:56:54 +03:00
ts_secret_init ( ) ;
2017-03-24 21:42:37 +03:00
return siphash ( & combined , offsetofend ( typeof ( combined ) , daddr ) ,
& ts_secret ) ;
}
2017-05-05 16:56:54 +03:00
EXPORT_SYMBOL ( secure_tcpv6_ts_off ) ;
2017-03-24 21:42:37 +03:00
2017-05-05 16:56:54 +03:00
u32 secure_tcpv6_seq ( const __be32 * saddr , const __be32 * daddr ,
__be16 sport , __be16 dport )
2011-08-04 07:50:44 +04:00
{
2017-01-08 15:54:02 +03:00
const struct {
struct in6_addr saddr ;
struct in6_addr daddr ;
__be16 sport ;
__be16 dport ;
} __aligned ( SIPHASH_ALIGNMENT ) combined = {
. saddr = * ( struct in6_addr * ) saddr ,
. daddr = * ( struct in6_addr * ) daddr ,
. sport = sport ,
. dport = dport
} ;
2017-05-05 16:56:54 +03:00
u32 hash ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2017-01-08 15:54:02 +03:00
hash = siphash ( & combined , offsetofend ( typeof ( combined ) , dport ) ,
& net_secret ) ;
return seq_scale ( hash ) ;
2011-08-04 07:50:44 +04:00
}
2017-05-05 16:56:54 +03:00
EXPORT_SYMBOL ( secure_tcpv6_seq ) ;
2011-08-04 07:50:44 +04:00
u32 secure_ipv6_port_ephemeral ( const __be32 * saddr , const __be32 * daddr ,
__be16 dport )
{
2017-01-08 15:54:02 +03:00
const struct {
struct in6_addr saddr ;
struct in6_addr daddr ;
__be16 dport ;
} __aligned ( SIPHASH_ALIGNMENT ) combined = {
. saddr = * ( struct in6_addr * ) saddr ,
. daddr = * ( struct in6_addr * ) daddr ,
. dport = dport
} ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2017-01-08 15:54:02 +03:00
return siphash ( & combined , offsetofend ( typeof ( combined ) , dport ) ,
& net_secret ) ;
2011-08-04 07:50:44 +04:00
}
2012-08-26 21:14:12 +04:00
EXPORT_SYMBOL ( secure_ipv6_port_ephemeral ) ;
2011-08-04 07:50:44 +04:00
# endif
# ifdef CONFIG_INET
2017-06-07 20:34:39 +03:00
u32 secure_tcp_ts_off ( const struct net * net , __be32 saddr , __be32 daddr )
2017-03-24 21:42:37 +03:00
{
2017-06-07 20:34:39 +03:00
if ( net - > ipv4 . sysctl_tcp_timestamps ! = 1 )
2017-03-24 21:42:37 +03:00
return 0 ;
2017-05-05 16:56:54 +03:00
ts_secret_init ( ) ;
2017-03-24 21:42:37 +03:00
return siphash_2u32 ( ( __force u32 ) saddr , ( __force u32 ) daddr ,
& ts_secret ) ;
}
2011-08-04 07:50:44 +04:00
2017-03-09 13:53:55 +03:00
/* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d),
2017-01-08 15:54:02 +03:00
* but fortunately , ` sport ' cannot be 0 in any circumstances . If this changes ,
* it would be easy enough to have the former function use siphash_4u32 , passing
* the arguments as separate u32 .
*/
2017-05-05 16:56:54 +03:00
u32 secure_tcp_seq ( __be32 saddr , __be32 daddr ,
__be16 sport , __be16 dport )
2011-08-04 07:50:44 +04:00
{
2017-05-05 16:56:54 +03:00
u32 hash ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2017-01-08 15:54:02 +03:00
hash = siphash_3u32 ( ( __force u32 ) saddr , ( __force u32 ) daddr ,
( __force u32 ) sport < < 16 | ( __force u32 ) dport ,
& net_secret ) ;
return seq_scale ( hash ) ;
2011-08-04 07:50:44 +04:00
}
infiniband: i40iw, nes: don't use wall time for TCP sequence numbers
The nes infiniband driver uses current_kernel_time() to get a nanosecond
granunarity timestamp to initialize its tcp sequence counters. This is
one of only a few remaining users of that deprecated function, so we
should try to get rid of it.
Aside from using a deprecated API, there are several problems I see here:
- Using a CLOCK_REALTIME based time source makes it predictable in
case the time base is synchronized.
- Using a coarse timestamp means it only gets updated once per jiffie,
making it even more predictable in order to avoid having to access
the hardware clock source
- The upper 2 bits are always zero because the nanoseconds are at most
999999999.
For the Linux TCP implementation, we use secure_tcp_seq(), which appears
to be appropriate here as well, and solves all the above problems.
i40iw uses a variant of the same code, so I do that same thing there
for ipv4. Unlike nes, i40e also supports ipv6, which needs to call
secure_tcpv6_seq instead.
Acked-by: Shiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
2018-07-09 11:34:43 +03:00
EXPORT_SYMBOL_GPL ( secure_tcp_seq ) ;
2011-08-04 07:50:44 +04:00
u32 secure_ipv4_port_ephemeral ( __be32 saddr , __be32 daddr , __be16 dport )
{
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2017-01-08 15:54:02 +03:00
return siphash_3u32 ( ( __force u32 ) saddr , ( __force u32 ) daddr ,
( __force u16 ) dport , & net_secret ) ;
2011-08-04 07:50:44 +04:00
}
EXPORT_SYMBOL_GPL ( secure_ipv4_port_ephemeral ) ;
# endif
2011-12-12 06:58:22 +04:00
# if IS_ENABLED(CONFIG_IP_DCCP)
2011-08-04 07:50:44 +04:00
u64 secure_dccp_sequence_number ( __be32 saddr , __be32 daddr ,
__be16 sport , __be16 dport )
{
u64 seq ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2017-01-12 05:10:37 +03:00
seq = siphash_3u32 ( ( __force u32 ) saddr , ( __force u32 ) daddr ,
( __force u32 ) sport < < 16 | ( __force u32 ) dport ,
& net_secret ) ;
2014-08-23 05:32:09 +04:00
seq + = ktime_get_real_ns ( ) ;
2011-08-04 07:50:44 +04:00
seq & = ( 1ull < < 48 ) - 1 ;
return seq ;
}
EXPORT_SYMBOL ( secure_dccp_sequence_number ) ;
2011-12-10 13:48:31 +04:00
# if IS_ENABLED(CONFIG_IPV6)
2011-08-04 07:50:44 +04:00
u64 secure_dccpv6_sequence_number ( __be32 * saddr , __be32 * daddr ,
__be16 sport , __be16 dport )
{
2017-01-08 15:54:02 +03:00
const struct {
struct in6_addr saddr ;
struct in6_addr daddr ;
__be16 sport ;
__be16 dport ;
} __aligned ( SIPHASH_ALIGNMENT ) combined = {
. saddr = * ( struct in6_addr * ) saddr ,
. daddr = * ( struct in6_addr * ) daddr ,
. sport = sport ,
. dport = dport
} ;
2011-08-04 07:50:44 +04:00
u64 seq ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2017-01-08 15:54:02 +03:00
seq = siphash ( & combined , offsetofend ( typeof ( combined ) , dport ) ,
& net_secret ) ;
2014-08-23 05:32:09 +04:00
seq + = ktime_get_real_ns ( ) ;
2011-08-04 07:50:44 +04:00
seq & = ( 1ull < < 48 ) - 1 ;
return seq ;
}
EXPORT_SYMBOL ( secure_dccpv6_sequence_number ) ;
# endif
# endif