summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2019-06-19 17:46:28 -0400
committerDavid S. Miller <davem@davemloft.net>2019-06-22 19:30:37 -0400
commit438ac88009bcb10f9ced07fbb4b32d5377ee936b (patch)
treea28dc489c5852e2894a04478bdd0f37ffe010ad5
parent92ad6325cb891bb455487bfe90cc47d18aa6ec37 (diff)
net: fastopen: robustness and endianness fixes for SipHash
Some changes to the TCP fastopen code to make it more robust against future changes in the choice of key/cookie size, etc. - Instead of keeping the SipHash key in an untyped u8[] buffer and casting it to the right type upon use, use the correct type directly. This ensures that the key will appear at the correct alignment if we ever change the way these data structures are allocated. (Currently, they are only allocated via kmalloc so they always appear at the correct alignment) - Use DIV_ROUND_UP when sizing the u64[] array to hold the cookie, so it is always of sufficient size, even if TCP_FASTOPEN_COOKIE_MAX is no longer a multiple of 8. - Drop the 'len' parameter from the tcp_fastopen_reset_cipher() function, which is no longer used. - Add endian swabbing when setting the keys and calculating the hash, to ensure that cookie values are the same for a given key and source/destination address pair regardless of the endianness of the server. Note that none of these are functional changes wrt the current state of the code, with the exception of the swabbing, which only affects big endian systems. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/tcp.h2
-rw-r--r--include/net/tcp.h8
-rw-r--r--net/ipv4/sysctl_net_ipv4.c3
-rw-r--r--net/ipv4/tcp.c3
-rw-r--r--net/ipv4/tcp_fastopen.c35
5 files changed, 24 insertions, 27 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 2689b0b0b68a..f3a85a7fb4b1 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -58,7 +58,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb)
58 58
59/* TCP Fast Open Cookie as stored in memory */ 59/* TCP Fast Open Cookie as stored in memory */
60struct tcp_fastopen_cookie { 60struct tcp_fastopen_cookie {
61 u64 val[TCP_FASTOPEN_COOKIE_MAX / sizeof(u64)]; 61 __le64 val[DIV_ROUND_UP(TCP_FASTOPEN_COOKIE_MAX, sizeof(u64))];
62 s8 len; 62 s8 len;
63 bool exp; /* In RFC6994 experimental option format */ 63 bool exp; /* In RFC6994 experimental option format */
64}; 64};
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 573c9e9b0d72..9d36cc88d043 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -43,6 +43,7 @@
43#include <linux/seq_file.h> 43#include <linux/seq_file.h>
44#include <linux/memcontrol.h> 44#include <linux/memcontrol.h>
45#include <linux/bpf-cgroup.h> 45#include <linux/bpf-cgroup.h>
46#include <linux/siphash.h>
46 47
47extern struct inet_hashinfo tcp_hashinfo; 48extern struct inet_hashinfo tcp_hashinfo;
48 49
@@ -1612,8 +1613,7 @@ void tcp_free_fastopen_req(struct tcp_sock *tp);
1612void tcp_fastopen_destroy_cipher(struct sock *sk); 1613void tcp_fastopen_destroy_cipher(struct sock *sk);
1613void tcp_fastopen_ctx_destroy(struct net *net); 1614void tcp_fastopen_ctx_destroy(struct net *net);
1614int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, 1615int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
1615 void *primary_key, void *backup_key, 1616 void *primary_key, void *backup_key);
1616 unsigned int len);
1617void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb); 1617void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb);
1618struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb, 1618struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
1619 struct request_sock *req, 1619 struct request_sock *req,
@@ -1623,14 +1623,14 @@ void tcp_fastopen_init_key_once(struct net *net);
1623bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss, 1623bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
1624 struct tcp_fastopen_cookie *cookie); 1624 struct tcp_fastopen_cookie *cookie);
1625bool tcp_fastopen_defer_connect(struct sock *sk, int *err); 1625bool tcp_fastopen_defer_connect(struct sock *sk, int *err);
1626#define TCP_FASTOPEN_KEY_LENGTH 16 1626#define TCP_FASTOPEN_KEY_LENGTH sizeof(siphash_key_t)
1627#define TCP_FASTOPEN_KEY_MAX 2 1627#define TCP_FASTOPEN_KEY_MAX 2
1628#define TCP_FASTOPEN_KEY_BUF_LENGTH \ 1628#define TCP_FASTOPEN_KEY_BUF_LENGTH \
1629 (TCP_FASTOPEN_KEY_LENGTH * TCP_FASTOPEN_KEY_MAX) 1629 (TCP_FASTOPEN_KEY_LENGTH * TCP_FASTOPEN_KEY_MAX)
1630 1630
1631/* Fastopen key context */ 1631/* Fastopen key context */
1632struct tcp_fastopen_context { 1632struct tcp_fastopen_context {
1633 __u8 key[TCP_FASTOPEN_KEY_MAX][TCP_FASTOPEN_KEY_LENGTH]; 1633 siphash_key_t key[TCP_FASTOPEN_KEY_MAX];
1634 int num; 1634 int num;
1635 struct rcu_head rcu; 1635 struct rcu_head rcu;
1636}; 1636};
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7d802acde040..7d66306b5f39 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -365,8 +365,7 @@ static int proc_tcp_fastopen_key(struct ctl_table *table, int write,
365 } 365 }
366 } 366 }
367 tcp_fastopen_reset_cipher(net, NULL, key, 367 tcp_fastopen_reset_cipher(net, NULL, key,
368 backup_data ? key + 4 : NULL, 368 backup_data ? key + 4 : NULL);
369 TCP_FASTOPEN_KEY_LENGTH);
370 } 369 }
371 370
372bad_key: 371bad_key:
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index efd7f2b1d1f0..47c217905864 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2822,8 +2822,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
2822 if (optlen == TCP_FASTOPEN_KEY_BUF_LENGTH) 2822 if (optlen == TCP_FASTOPEN_KEY_BUF_LENGTH)
2823 backup_key = key + TCP_FASTOPEN_KEY_LENGTH; 2823 backup_key = key + TCP_FASTOPEN_KEY_LENGTH;
2824 2824
2825 return tcp_fastopen_reset_cipher(net, sk, key, backup_key, 2825 return tcp_fastopen_reset_cipher(net, sk, key, backup_key);
2826 TCP_FASTOPEN_KEY_LENGTH);
2827 } 2826 }
2828 default: 2827 default:
2829 /* fallthru */ 2828 /* fallthru */
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
index f918599181dd..3fd451271a70 100644
--- a/net/ipv4/tcp_fastopen.c
+++ b/net/ipv4/tcp_fastopen.c
@@ -7,7 +7,6 @@
7#include <linux/tcp.h> 7#include <linux/tcp.h>
8#include <linux/rcupdate.h> 8#include <linux/rcupdate.h>
9#include <linux/rculist.h> 9#include <linux/rculist.h>
10#include <linux/siphash.h>
11#include <net/inetpeer.h> 10#include <net/inetpeer.h>
12#include <net/tcp.h> 11#include <net/tcp.h>
13 12
@@ -31,7 +30,7 @@ void tcp_fastopen_init_key_once(struct net *net)
31 * for a valid cookie, so this is an acceptable risk. 30 * for a valid cookie, so this is an acceptable risk.
32 */ 31 */
33 get_random_bytes(key, sizeof(key)); 32 get_random_bytes(key, sizeof(key));
34 tcp_fastopen_reset_cipher(net, NULL, key, NULL, sizeof(key)); 33 tcp_fastopen_reset_cipher(net, NULL, key, NULL);
35} 34}
36 35
37static void tcp_fastopen_ctx_free(struct rcu_head *head) 36static void tcp_fastopen_ctx_free(struct rcu_head *head)
@@ -68,8 +67,7 @@ void tcp_fastopen_ctx_destroy(struct net *net)
68} 67}
69 68
70int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, 69int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
71 void *primary_key, void *backup_key, 70 void *primary_key, void *backup_key)
72 unsigned int len)
73{ 71{
74 struct tcp_fastopen_context *ctx, *octx; 72 struct tcp_fastopen_context *ctx, *octx;
75 struct fastopen_queue *q; 73 struct fastopen_queue *q;
@@ -81,9 +79,11 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
81 goto out; 79 goto out;
82 } 80 }
83 81
84 memcpy(ctx->key[0], primary_key, len); 82 ctx->key[0].key[0] = get_unaligned_le64(primary_key);
83 ctx->key[0].key[1] = get_unaligned_le64(primary_key + 8);
85 if (backup_key) { 84 if (backup_key) {
86 memcpy(ctx->key[1], backup_key, len); 85 ctx->key[1].key[0] = get_unaligned_le64(backup_key);
86 ctx->key[1].key[1] = get_unaligned_le64(backup_key + 8);
87 ctx->num = 2; 87 ctx->num = 2;
88 } else { 88 } else {
89 ctx->num = 1; 89 ctx->num = 1;
@@ -110,19 +110,18 @@ out:
110 110
111static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req, 111static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req,
112 struct sk_buff *syn, 112 struct sk_buff *syn,
113 const u8 *key, 113 const siphash_key_t *key,
114 struct tcp_fastopen_cookie *foc) 114 struct tcp_fastopen_cookie *foc)
115{ 115{
116 BUILD_BUG_ON(TCP_FASTOPEN_KEY_LENGTH != sizeof(siphash_key_t));
117 BUILD_BUG_ON(TCP_FASTOPEN_COOKIE_SIZE != sizeof(u64)); 116 BUILD_BUG_ON(TCP_FASTOPEN_COOKIE_SIZE != sizeof(u64));
118 117
119 if (req->rsk_ops->family == AF_INET) { 118 if (req->rsk_ops->family == AF_INET) {
120 const struct iphdr *iph = ip_hdr(syn); 119 const struct iphdr *iph = ip_hdr(syn);
121 120
122 foc->val[0] = siphash(&iph->saddr, 121 foc->val[0] = cpu_to_le64(siphash(&iph->saddr,
123 sizeof(iph->saddr) + 122 sizeof(iph->saddr) +
124 sizeof(iph->daddr), 123 sizeof(iph->daddr),
125 (const siphash_key_t *)key); 124 key));
126 foc->len = TCP_FASTOPEN_COOKIE_SIZE; 125 foc->len = TCP_FASTOPEN_COOKIE_SIZE;
127 return true; 126 return true;
128 } 127 }
@@ -130,10 +129,10 @@ static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req,
130 if (req->rsk_ops->family == AF_INET6) { 129 if (req->rsk_ops->family == AF_INET6) {
131 const struct ipv6hdr *ip6h = ipv6_hdr(syn); 130 const struct ipv6hdr *ip6h = ipv6_hdr(syn);
132 131
133 foc->val[0] = siphash(&ip6h->saddr, 132 foc->val[0] = cpu_to_le64(siphash(&ip6h->saddr,
134 sizeof(ip6h->saddr) + 133 sizeof(ip6h->saddr) +
135 sizeof(ip6h->daddr), 134 sizeof(ip6h->daddr),
136 (const siphash_key_t *)key); 135 key));
137 foc->len = TCP_FASTOPEN_COOKIE_SIZE; 136 foc->len = TCP_FASTOPEN_COOKIE_SIZE;
138 return true; 137 return true;
139 } 138 }
@@ -154,7 +153,7 @@ static void tcp_fastopen_cookie_gen(struct sock *sk,
154 rcu_read_lock(); 153 rcu_read_lock();
155 ctx = tcp_fastopen_get_ctx(sk); 154 ctx = tcp_fastopen_get_ctx(sk);
156 if (ctx) 155 if (ctx)
157 __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->key[0], foc); 156 __tcp_fastopen_cookie_gen_cipher(req, syn, &ctx->key[0], foc);
158 rcu_read_unlock(); 157 rcu_read_unlock();
159} 158}
160 159
@@ -218,7 +217,7 @@ static int tcp_fastopen_cookie_gen_check(struct sock *sk,
218 if (!ctx) 217 if (!ctx)
219 goto out; 218 goto out;
220 for (i = 0; i < tcp_fastopen_context_len(ctx); i++) { 219 for (i = 0; i < tcp_fastopen_context_len(ctx); i++) {
221 __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->key[i], foc); 220 __tcp_fastopen_cookie_gen_cipher(req, syn, &ctx->key[i], foc);
222 if (tcp_fastopen_cookie_match(foc, orig)) { 221 if (tcp_fastopen_cookie_match(foc, orig)) {
223 ret = i + 1; 222 ret = i + 1;
224 goto out; 223 goto out;