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