secure_seq.c 5.1 KB

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