at v4.12-rc1 4.9 kB view raw
1/* 2 * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 3 */ 4 5#include <linux/kernel.h> 6#include <linux/init.h> 7#include <linux/cryptohash.h> 8#include <linux/module.h> 9#include <linux/cache.h> 10#include <linux/random.h> 11#include <linux/hrtimer.h> 12#include <linux/ktime.h> 13#include <linux/string.h> 14#include <linux/net.h> 15#include <linux/siphash.h> 16#include <net/secure_seq.h> 17 18#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET) 19#include <linux/in6.h> 20#include <net/tcp.h> 21 22static siphash_key_t net_secret __read_mostly; 23static siphash_key_t ts_secret __read_mostly; 24 25static __always_inline void net_secret_init(void) 26{ 27 net_get_random_once(&net_secret, sizeof(net_secret)); 28} 29 30static __always_inline void ts_secret_init(void) 31{ 32 net_get_random_once(&ts_secret, sizeof(ts_secret)); 33} 34#endif 35 36#ifdef CONFIG_INET 37static u32 seq_scale(u32 seq) 38{ 39 /* 40 * As close as possible to RFC 793, which 41 * suggests using a 250 kHz clock. 42 * Further reading shows this assumes 2 Mb/s networks. 43 * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. 44 * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but 45 * we also need to limit the resolution so that the u32 seq 46 * overlaps less than one time per MSL (2 minutes). 47 * Choosing a clock of 64 ns period is OK. (period of 274 s) 48 */ 49 return seq + (ktime_get_real_ns() >> 6); 50} 51#endif 52 53#if IS_ENABLED(CONFIG_IPV6) 54u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr) 55{ 56 const struct { 57 struct in6_addr saddr; 58 struct in6_addr daddr; 59 } __aligned(SIPHASH_ALIGNMENT) combined = { 60 .saddr = *(struct in6_addr *)saddr, 61 .daddr = *(struct in6_addr *)daddr, 62 }; 63 64 if (sysctl_tcp_timestamps != 1) 65 return 0; 66 67 ts_secret_init(); 68 return siphash(&combined, offsetofend(typeof(combined), daddr), 69 &ts_secret); 70} 71EXPORT_SYMBOL(secure_tcpv6_ts_off); 72 73u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr, 74 __be16 sport, __be16 dport) 75{ 76 const struct { 77 struct in6_addr saddr; 78 struct in6_addr daddr; 79 __be16 sport; 80 __be16 dport; 81 } __aligned(SIPHASH_ALIGNMENT) combined = { 82 .saddr = *(struct in6_addr *)saddr, 83 .daddr = *(struct in6_addr *)daddr, 84 .sport = sport, 85 .dport = dport 86 }; 87 u32 hash; 88 89 net_secret_init(); 90 hash = siphash(&combined, offsetofend(typeof(combined), dport), 91 &net_secret); 92 return seq_scale(hash); 93} 94EXPORT_SYMBOL(secure_tcpv6_seq); 95 96u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, 97 __be16 dport) 98{ 99 const struct { 100 struct in6_addr saddr; 101 struct in6_addr daddr; 102 __be16 dport; 103 } __aligned(SIPHASH_ALIGNMENT) combined = { 104 .saddr = *(struct in6_addr *)saddr, 105 .daddr = *(struct in6_addr *)daddr, 106 .dport = dport 107 }; 108 net_secret_init(); 109 return siphash(&combined, offsetofend(typeof(combined), dport), 110 &net_secret); 111} 112EXPORT_SYMBOL(secure_ipv6_port_ephemeral); 113#endif 114 115#ifdef CONFIG_INET 116u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr) 117{ 118 if (sysctl_tcp_timestamps != 1) 119 return 0; 120 121 ts_secret_init(); 122 return siphash_2u32((__force u32)saddr, (__force u32)daddr, 123 &ts_secret); 124} 125 126/* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), 127 * but fortunately, `sport' cannot be 0 in any circumstances. If this changes, 128 * it would be easy enough to have the former function use siphash_4u32, passing 129 * the arguments as separate u32. 130 */ 131u32 secure_tcp_seq(__be32 saddr, __be32 daddr, 132 __be16 sport, __be16 dport) 133{ 134 u32 hash; 135 136 net_secret_init(); 137 hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, 138 (__force u32)sport << 16 | (__force u32)dport, 139 &net_secret); 140 return seq_scale(hash); 141} 142 143u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) 144{ 145 net_secret_init(); 146 return siphash_3u32((__force u32)saddr, (__force u32)daddr, 147 (__force u16)dport, &net_secret); 148} 149EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); 150#endif 151 152#if IS_ENABLED(CONFIG_IP_DCCP) 153u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, 154 __be16 sport, __be16 dport) 155{ 156 u64 seq; 157 net_secret_init(); 158 seq = siphash_3u32((__force u32)saddr, (__force u32)daddr, 159 (__force u32)sport << 16 | (__force u32)dport, 160 &net_secret); 161 seq += ktime_get_real_ns(); 162 seq &= (1ull << 48) - 1; 163 return seq; 164} 165EXPORT_SYMBOL(secure_dccp_sequence_number); 166 167#if IS_ENABLED(CONFIG_IPV6) 168u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, 169 __be16 sport, __be16 dport) 170{ 171 const struct { 172 struct in6_addr saddr; 173 struct in6_addr daddr; 174 __be16 sport; 175 __be16 dport; 176 } __aligned(SIPHASH_ALIGNMENT) combined = { 177 .saddr = *(struct in6_addr *)saddr, 178 .daddr = *(struct in6_addr *)daddr, 179 .sport = sport, 180 .dport = dport 181 }; 182 u64 seq; 183 net_secret_init(); 184 seq = siphash(&combined, offsetofend(typeof(combined), dport), 185 &net_secret); 186 seq += ktime_get_real_ns(); 187 seq &= (1ull << 48) - 1; 188 return seq; 189} 190EXPORT_SYMBOL(secure_dccpv6_sequence_number); 191#endif 192#endif