Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/cache.h>
0010 #include <linux/random.h>
0011 #include <linux/hrtimer.h>
0012 #include <linux/ktime.h>
0013 #include <linux/string.h>
0014 #include <linux/net.h>
0015 #include <linux/siphash.h>
0016 #include <net/secure_seq.h>
0017 
0018 #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
0019 #include <linux/in6.h>
0020 #include <net/tcp.h>
0021 
0022 static siphash_aligned_key_t net_secret;
0023 static siphash_aligned_key_t ts_secret;
0024 
0025 #define EPHEMERAL_PORT_SHUFFLE_PERIOD (10 * HZ)
0026 
0027 static __always_inline void net_secret_init(void)
0028 {
0029     net_get_random_once(&net_secret, sizeof(net_secret));
0030 }
0031 
0032 static __always_inline void ts_secret_init(void)
0033 {
0034     net_get_random_once(&ts_secret, sizeof(ts_secret));
0035 }
0036 #endif
0037 
0038 #ifdef CONFIG_INET
0039 static u32 seq_scale(u32 seq)
0040 {
0041     /*
0042      *  As close as possible to RFC 793, which
0043      *  suggests using a 250 kHz clock.
0044      *  Further reading shows this assumes 2 Mb/s networks.
0045      *  For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
0046      *  For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
0047      *  we also need to limit the resolution so that the u32 seq
0048      *  overlaps less than one time per MSL (2 minutes).
0049      *  Choosing a clock of 64 ns period is OK. (period of 274 s)
0050      */
0051     return seq + (ktime_get_real_ns() >> 6);
0052 }
0053 #endif
0054 
0055 #if IS_ENABLED(CONFIG_IPV6)
0056 u32 secure_tcpv6_ts_off(const struct net *net,
0057             const __be32 *saddr, const __be32 *daddr)
0058 {
0059     const struct {
0060         struct in6_addr saddr;
0061         struct in6_addr daddr;
0062     } __aligned(SIPHASH_ALIGNMENT) combined = {
0063         .saddr = *(struct in6_addr *)saddr,
0064         .daddr = *(struct in6_addr *)daddr,
0065     };
0066 
0067     if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
0068         return 0;
0069 
0070     ts_secret_init();
0071     return siphash(&combined, offsetofend(typeof(combined), daddr),
0072                &ts_secret);
0073 }
0074 EXPORT_SYMBOL(secure_tcpv6_ts_off);
0075 
0076 u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
0077              __be16 sport, __be16 dport)
0078 {
0079     const struct {
0080         struct in6_addr saddr;
0081         struct in6_addr daddr;
0082         __be16 sport;
0083         __be16 dport;
0084     } __aligned(SIPHASH_ALIGNMENT) combined = {
0085         .saddr = *(struct in6_addr *)saddr,
0086         .daddr = *(struct in6_addr *)daddr,
0087         .sport = sport,
0088         .dport = dport
0089     };
0090     u32 hash;
0091 
0092     net_secret_init();
0093     hash = siphash(&combined, offsetofend(typeof(combined), dport),
0094                &net_secret);
0095     return seq_scale(hash);
0096 }
0097 EXPORT_SYMBOL(secure_tcpv6_seq);
0098 
0099 u64 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
0100                    __be16 dport)
0101 {
0102     const struct {
0103         struct in6_addr saddr;
0104         struct in6_addr daddr;
0105         unsigned int timeseed;
0106         __be16 dport;
0107     } __aligned(SIPHASH_ALIGNMENT) combined = {
0108         .saddr = *(struct in6_addr *)saddr,
0109         .daddr = *(struct in6_addr *)daddr,
0110         .timeseed = jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD,
0111         .dport = dport,
0112     };
0113     net_secret_init();
0114     return siphash(&combined, offsetofend(typeof(combined), dport),
0115                &net_secret);
0116 }
0117 EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
0118 #endif
0119 
0120 #ifdef CONFIG_INET
0121 u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
0122 {
0123     if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
0124         return 0;
0125 
0126     ts_secret_init();
0127     return siphash_2u32((__force u32)saddr, (__force u32)daddr,
0128                 &ts_secret);
0129 }
0130 
0131 /* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d),
0132  * but fortunately, `sport' cannot be 0 in any circumstances. If this changes,
0133  * it would be easy enough to have the former function use siphash_4u32, passing
0134  * the arguments as separate u32.
0135  */
0136 u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
0137            __be16 sport, __be16 dport)
0138 {
0139     u32 hash;
0140 
0141     net_secret_init();
0142     hash = siphash_3u32((__force u32)saddr, (__force u32)daddr,
0143                 (__force u32)sport << 16 | (__force u32)dport,
0144                 &net_secret);
0145     return seq_scale(hash);
0146 }
0147 EXPORT_SYMBOL_GPL(secure_tcp_seq);
0148 
0149 u64 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
0150 {
0151     net_secret_init();
0152     return siphash_4u32((__force u32)saddr, (__force u32)daddr,
0153                 (__force u16)dport,
0154                 jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD,
0155                 &net_secret);
0156 }
0157 EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
0158 #endif
0159 
0160 #if IS_ENABLED(CONFIG_IP_DCCP)
0161 u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
0162                 __be16 sport, __be16 dport)
0163 {
0164     u64 seq;
0165     net_secret_init();
0166     seq = siphash_3u32((__force u32)saddr, (__force u32)daddr,
0167                (__force u32)sport << 16 | (__force u32)dport,
0168                &net_secret);
0169     seq += ktime_get_real_ns();
0170     seq &= (1ull << 48) - 1;
0171     return seq;
0172 }
0173 EXPORT_SYMBOL(secure_dccp_sequence_number);
0174 
0175 #if IS_ENABLED(CONFIG_IPV6)
0176 u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
0177                   __be16 sport, __be16 dport)
0178 {
0179     const struct {
0180         struct in6_addr saddr;
0181         struct in6_addr daddr;
0182         __be16 sport;
0183         __be16 dport;
0184     } __aligned(SIPHASH_ALIGNMENT) combined = {
0185         .saddr = *(struct in6_addr *)saddr,
0186         .daddr = *(struct in6_addr *)daddr,
0187         .sport = sport,
0188         .dport = dport
0189     };
0190     u64 seq;
0191     net_secret_init();
0192     seq = siphash(&combined, offsetofend(typeof(combined), dport),
0193               &net_secret);
0194     seq += ktime_get_real_ns();
0195     seq &= (1ull << 48) - 1;
0196     return seq;
0197 }
0198 EXPORT_SYMBOL(secure_dccpv6_sequence_number);
0199 #endif
0200 #endif