History

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.

Ard Biesheuvel committed 7 years ago

Commit 438ac881 parent 92ad6325 files · +24 −27Browse files

Unified · Split

5 files
  1. include/linux/tcp.h +1 −1
  2. include/net/tcp.h +4 −4
  3. net/ipv4/sysctl_net_ipv4.c +1 −2
  4. net/ipv4/tcp.c +1 −2
  5. net/ipv4/tcp_fastopen.c +17 −18
include/linux/tcp.h+1−1
@@ -58,7 +58,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) · 57 unmodified lines
5858
5959 /* TCP Fast Open Cookie as stored in memory */
6060 struct tcp_fastopen_cookie {
61− u64 val[TCP_FASTOPEN_COOKIE_MAX / sizeof(u64)];
61+ __le64 val[DIV_ROUND_UP(TCP_FASTOPEN_COOKIE_MAX, sizeof(u64))];
6262 s8 len;
6363 bool exp; /* In RFC6994 experimental option format */
6464 };
include/net/tcp.h+4−4
@@ -43,6 +43,7 @@ · 42 unmodified lines
4343 #include <linux/seq_file.h>
4444 #include <linux/memcontrol.h>
4545 #include <linux/bpf-cgroup.h>
46+#include <linux/siphash.h>
4647
4748 extern struct inet_hashinfo tcp_hashinfo;
4849
@@ -1612,8 +1613,7 @@ void tcp_free_fastopen_req(struct tcp_sock *tp); · 1563 unmodified lines
16121613 void tcp_fastopen_destroy_cipher(struct sock *sk);
16131614 void tcp_fastopen_ctx_destroy(struct net *net);
16141615 int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
1615− void *primary_key, void *backup_key,
1616− unsigned int len);
1616+ void *primary_key, void *backup_key);
16171617 void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb);
16181618 struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
16191619 struct request_sock *req,
@@ -1623,14 +1623,14 @@ void tcp_fastopen_init_key_once(struct net *net); · 3 unmodified lines
16231623 bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
16241624 struct tcp_fastopen_cookie *cookie);
16251625 bool 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)
16271627 #define TCP_FASTOPEN_KEY_MAX 2
16281628 #define TCP_FASTOPEN_KEY_BUF_LENGTH \
16291629 (TCP_FASTOPEN_KEY_LENGTH * TCP_FASTOPEN_KEY_MAX)
16301630
16311631 /* Fastopen key context */
16321632 struct tcp_fastopen_context {
1633− __u8 key[TCP_FASTOPEN_KEY_MAX][TCP_FASTOPEN_KEY_LENGTH];
1633+ siphash_key_t key[TCP_FASTOPEN_KEY_MAX];
16341634 int num;
16351635 struct rcu_head rcu;
16361636 };
net/ipv4/sysctl_net_ipv4.c+1−2
@@ -365,8 +365,7 @@ static int proc_tcp_fastopen_key(struct ctl_table *table, int write, · 364 unmodified lines
365365 }
366366 }
367367 tcp_fastopen_reset_cipher(net, NULL, key,
368− backup_data ? key + 4 : NULL,
369− TCP_FASTOPEN_KEY_LENGTH);
368+ backup_data ? key + 4 : NULL);
370369 }
371370
372371 bad_key:
net/ipv4/tcp.c+1−2
@@ -2822,8 +2822,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, · 2821 unmodified lines
28222822 if (optlen == TCP_FASTOPEN_KEY_BUF_LENGTH)
28232823 backup_key = key + TCP_FASTOPEN_KEY_LENGTH;
28242824
2825− return tcp_fastopen_reset_cipher(net, sk, key, backup_key,
2826− TCP_FASTOPEN_KEY_LENGTH);
2825+ return tcp_fastopen_reset_cipher(net, sk, key, backup_key);
28272826 }
28282827 default:
28292828 /* fallthru */
net/ipv4/tcp_fastopen.c+17−18
@@ -7,7 +7,6 @@ · 6 unmodified lines
77 #include <linux/tcp.h>
88 #include <linux/rcupdate.h>
99 #include <linux/rculist.h>
10−#include <linux/siphash.h>
1110 #include <net/inetpeer.h>
1211 #include <net/tcp.h>
1312
@@ -31,7 +30,7 @@ void tcp_fastopen_init_key_once(struct net *net) · 17 unmodified lines
3130 * for a valid cookie, so this is an acceptable risk.
3231 */
3332 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);
3534 }
3635
3736 static void tcp_fastopen_ctx_free(struct rcu_head *head)
@@ -68,8 +67,7 @@ void tcp_fastopen_ctx_destroy(struct net *net) · 30 unmodified lines
6867 }
6968
7069 int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
71− void *primary_key, void *backup_key,
72− unsigned int len)
70+ void *primary_key, void *backup_key)
7371 {
7472 struct tcp_fastopen_context *ctx, *octx;
7573 struct fastopen_queue *q;
@@ -81,9 +79,11 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, · 5 unmodified lines
8179 goto out;
8280 }
8381
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);
8584 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);
8787 ctx->num = 2;
8888 } else {
8989 ctx->num = 1;
@@ -110,19 +110,18 @@ out: · 20 unmodified lines
110110
111111 static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req,
112112 struct sk_buff *syn,
113− const u8 *key,
113+ const siphash_key_t *key,
114114 struct tcp_fastopen_cookie *foc)
115115 {
116− BUILD_BUG_ON(TCP_FASTOPEN_KEY_LENGTH != sizeof(siphash_key_t));
117116 BUILD_BUG_ON(TCP_FASTOPEN_COOKIE_SIZE != sizeof(u64));
118117
119118 if (req->rsk_ops->family == AF_INET) {
120119 const struct iphdr *iph = ip_hdr(syn);
121120
122− foc->val[0] = siphash(&iph->saddr,
123− sizeof(iph->saddr) +
124− sizeof(iph->daddr),
125− (const siphash_key_t *)key);
121+ foc->val[0] = cpu_to_le64(siphash(&iph->saddr,
122+ sizeof(iph->saddr) +
123+ sizeof(iph->daddr),
124+ key));
126125 foc->len = TCP_FASTOPEN_COOKIE_SIZE;
127126 return true;
128127 }
@@ -130,10 +129,10 @@ static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req, · 1 unmodified line
130129 if (req->rsk_ops->family == AF_INET6) {
131130 const struct ipv6hdr *ip6h = ipv6_hdr(syn);
132131
133− foc->val[0] = siphash(&ip6h->saddr,
134− sizeof(ip6h->saddr) +
135− sizeof(ip6h->daddr),
136− (const siphash_key_t *)key);
132+ foc->val[0] = cpu_to_le64(siphash(&ip6h->saddr,
133+ sizeof(ip6h->saddr) +
134+ sizeof(ip6h->daddr),
135+ key));
137136 foc->len = TCP_FASTOPEN_COOKIE_SIZE;
138137 return true;
139138 }
@@ -154,7 +153,7 @@ static void tcp_fastopen_cookie_gen(struct sock *sk, · 14 unmodified lines
154153 rcu_read_lock();
155154 ctx = tcp_fastopen_get_ctx(sk);
156155 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);
158157 rcu_read_unlock();
159158 }
160159
@@ -218,7 +217,7 @@ static int tcp_fastopen_cookie_gen_check(struct sock *sk, · 57 unmodified lines
218217 if (!ctx)
219218 goto out;
220219 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);
222221 if (tcp_fastopen_cookie_match(foc, orig)) {
223222 ret = i + 1;
224223 goto out;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t