diff options
-rw-r--r-- | include/linux/tcp.h | 7 | ||||
-rw-r--r-- | include/net/tcp.h | 10 | ||||
-rw-r--r-- | net/Kconfig | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 97 |
4 files changed, 36 insertions, 80 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h index c23019a3b264..9ea0e71f5c6a 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h | |||
@@ -58,12 +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 */ |
60 | struct tcp_fastopen_cookie { | 60 | struct tcp_fastopen_cookie { |
61 | union { | 61 | u64 val[TCP_FASTOPEN_COOKIE_MAX / sizeof(u64)]; |
62 | u8 val[TCP_FASTOPEN_COOKIE_MAX]; | ||
63 | #if IS_ENABLED(CONFIG_IPV6) | ||
64 | struct in6_addr addr; | ||
65 | #endif | ||
66 | }; | ||
67 | s8 len; | 62 | s8 len; |
68 | bool exp; /* In RFC6994 experimental option format */ | 63 | bool exp; /* In RFC6994 experimental option format */ |
69 | }; | 64 | }; |
diff --git a/include/net/tcp.h b/include/net/tcp.h index 96e0e53ff440..184930b02779 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -1628,9 +1628,9 @@ bool tcp_fastopen_defer_connect(struct sock *sk, int *err); | |||
1628 | 1628 | ||
1629 | /* Fastopen key context */ | 1629 | /* Fastopen key context */ |
1630 | struct tcp_fastopen_context { | 1630 | struct tcp_fastopen_context { |
1631 | struct crypto_cipher *tfm[TCP_FASTOPEN_KEY_MAX]; | 1631 | __u8 key[TCP_FASTOPEN_KEY_MAX][TCP_FASTOPEN_KEY_LENGTH]; |
1632 | __u8 key[TCP_FASTOPEN_KEY_BUF_LENGTH]; | 1632 | int num; |
1633 | struct rcu_head rcu; | 1633 | struct rcu_head rcu; |
1634 | }; | 1634 | }; |
1635 | 1635 | ||
1636 | extern unsigned int sysctl_tcp_fastopen_blackhole_timeout; | 1636 | extern unsigned int sysctl_tcp_fastopen_blackhole_timeout; |
@@ -1665,9 +1665,7 @@ bool tcp_fastopen_cookie_match(const struct tcp_fastopen_cookie *foc, | |||
1665 | static inline | 1665 | static inline |
1666 | int tcp_fastopen_context_len(const struct tcp_fastopen_context *ctx) | 1666 | int tcp_fastopen_context_len(const struct tcp_fastopen_context *ctx) |
1667 | { | 1667 | { |
1668 | if (ctx->tfm[1]) | 1668 | return ctx->num; |
1669 | return 2; | ||
1670 | return 1; | ||
1671 | } | 1669 | } |
1672 | 1670 | ||
1673 | /* Latencies incurred by various limits for a sender. They are | 1671 | /* Latencies incurred by various limits for a sender. They are |
diff --git a/net/Kconfig b/net/Kconfig index d122f53c6fa2..57f51a279ad6 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -67,8 +67,6 @@ source "net/xdp/Kconfig" | |||
67 | 67 | ||
68 | config INET | 68 | config INET |
69 | bool "TCP/IP networking" | 69 | bool "TCP/IP networking" |
70 | select CRYPTO | ||
71 | select CRYPTO_AES | ||
72 | ---help--- | 70 | ---help--- |
73 | These are the protocols used on the Internet and on most local | 71 | These are the protocols used on the Internet and on most local |
74 | Ethernets. It is highly recommended to say Y here (this will enlarge | 72 | Ethernets. It is highly recommended to say Y here (this will enlarge |
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 7d19fa4c8121..46b67128e1ca 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c | |||
@@ -7,6 +7,7 @@ | |||
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> | ||
10 | #include <net/inetpeer.h> | 11 | #include <net/inetpeer.h> |
11 | #include <net/tcp.h> | 12 | #include <net/tcp.h> |
12 | 13 | ||
@@ -37,14 +38,8 @@ static void tcp_fastopen_ctx_free(struct rcu_head *head) | |||
37 | { | 38 | { |
38 | struct tcp_fastopen_context *ctx = | 39 | struct tcp_fastopen_context *ctx = |
39 | container_of(head, struct tcp_fastopen_context, rcu); | 40 | container_of(head, struct tcp_fastopen_context, rcu); |
40 | int i; | ||
41 | 41 | ||
42 | /* We own ctx, thus no need to hold the Fastopen-lock */ | 42 | kzfree(ctx); |
43 | for (i = 0; i < TCP_FASTOPEN_KEY_MAX; i++) { | ||
44 | if (ctx->tfm[i]) | ||
45 | crypto_free_cipher(ctx->tfm[i]); | ||
46 | } | ||
47 | kfree(ctx); | ||
48 | } | 43 | } |
49 | 44 | ||
50 | void tcp_fastopen_destroy_cipher(struct sock *sk) | 45 | void tcp_fastopen_destroy_cipher(struct sock *sk) |
@@ -72,41 +67,6 @@ void tcp_fastopen_ctx_destroy(struct net *net) | |||
72 | call_rcu(&ctxt->rcu, tcp_fastopen_ctx_free); | 67 | call_rcu(&ctxt->rcu, tcp_fastopen_ctx_free); |
73 | } | 68 | } |
74 | 69 | ||
75 | static struct tcp_fastopen_context *tcp_fastopen_alloc_ctx(void *primary_key, | ||
76 | void *backup_key, | ||
77 | unsigned int len) | ||
78 | { | ||
79 | struct tcp_fastopen_context *new_ctx; | ||
80 | void *key = primary_key; | ||
81 | int err, i; | ||
82 | |||
83 | new_ctx = kmalloc(sizeof(*new_ctx), GFP_KERNEL); | ||
84 | if (!new_ctx) | ||
85 | return ERR_PTR(-ENOMEM); | ||
86 | for (i = 0; i < TCP_FASTOPEN_KEY_MAX; i++) | ||
87 | new_ctx->tfm[i] = NULL; | ||
88 | for (i = 0; i < (backup_key ? 2 : 1); i++) { | ||
89 | new_ctx->tfm[i] = crypto_alloc_cipher("aes", 0, 0); | ||
90 | if (IS_ERR(new_ctx->tfm[i])) { | ||
91 | err = PTR_ERR(new_ctx->tfm[i]); | ||
92 | new_ctx->tfm[i] = NULL; | ||
93 | pr_err("TCP: TFO aes cipher alloc error: %d\n", err); | ||
94 | goto out; | ||
95 | } | ||
96 | err = crypto_cipher_setkey(new_ctx->tfm[i], key, len); | ||
97 | if (err) { | ||
98 | pr_err("TCP: TFO cipher key error: %d\n", err); | ||
99 | goto out; | ||
100 | } | ||
101 | memcpy(&new_ctx->key[i * TCP_FASTOPEN_KEY_LENGTH], key, len); | ||
102 | key = backup_key; | ||
103 | } | ||
104 | return new_ctx; | ||
105 | out: | ||
106 | tcp_fastopen_ctx_free(&new_ctx->rcu); | ||
107 | return ERR_PTR(err); | ||
108 | } | ||
109 | |||
110 | int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, | 70 | int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, |
111 | void *primary_key, void *backup_key, | 71 | void *primary_key, void *backup_key, |
112 | unsigned int len) | 72 | unsigned int len) |
@@ -115,11 +75,20 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, | |||
115 | struct fastopen_queue *q; | 75 | struct fastopen_queue *q; |
116 | int err = 0; | 76 | int err = 0; |
117 | 77 | ||
118 | ctx = tcp_fastopen_alloc_ctx(primary_key, backup_key, len); | 78 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
119 | if (IS_ERR(ctx)) { | 79 | if (!ctx) { |
120 | err = PTR_ERR(ctx); | 80 | err = -ENOMEM; |
121 | goto out; | 81 | goto out; |
122 | } | 82 | } |
83 | |||
84 | memcpy(ctx->key[0], primary_key, len); | ||
85 | if (backup_key) { | ||
86 | memcpy(ctx->key[1], backup_key, len); | ||
87 | ctx->num = 2; | ||
88 | } else { | ||
89 | ctx->num = 1; | ||
90 | } | ||
91 | |||
123 | spin_lock(&net->ipv4.tcp_fastopen_ctx_lock); | 92 | spin_lock(&net->ipv4.tcp_fastopen_ctx_lock); |
124 | if (sk) { | 93 | if (sk) { |
125 | q = &inet_csk(sk)->icsk_accept_queue.fastopenq; | 94 | q = &inet_csk(sk)->icsk_accept_queue.fastopenq; |
@@ -141,31 +110,30 @@ out: | |||
141 | 110 | ||
142 | static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req, | 111 | static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req, |
143 | struct sk_buff *syn, | 112 | struct sk_buff *syn, |
144 | struct crypto_cipher *tfm, | 113 | const u8 *key, |
145 | struct tcp_fastopen_cookie *foc) | 114 | struct tcp_fastopen_cookie *foc) |
146 | { | 115 | { |
116 | BUILD_BUG_ON(TCP_FASTOPEN_KEY_LENGTH != sizeof(siphash_key_t)); | ||
117 | BUILD_BUG_ON(TCP_FASTOPEN_COOKIE_SIZE != sizeof(u64)); | ||
118 | |||
147 | if (req->rsk_ops->family == AF_INET) { | 119 | if (req->rsk_ops->family == AF_INET) { |
148 | const struct iphdr *iph = ip_hdr(syn); | 120 | const struct iphdr *iph = ip_hdr(syn); |
149 | __be32 path[4] = { iph->saddr, iph->daddr, 0, 0 }; | ||
150 | 121 | ||
151 | crypto_cipher_encrypt_one(tfm, foc->val, (void *)path); | 122 | foc->val[0] = siphash(&iph->saddr, |
123 | sizeof(iph->saddr) + | ||
124 | sizeof(iph->daddr), | ||
125 | (const siphash_key_t *)key); | ||
152 | foc->len = TCP_FASTOPEN_COOKIE_SIZE; | 126 | foc->len = TCP_FASTOPEN_COOKIE_SIZE; |
153 | return true; | 127 | return true; |
154 | } | 128 | } |
155 | |||
156 | #if IS_ENABLED(CONFIG_IPV6) | 129 | #if IS_ENABLED(CONFIG_IPV6) |
157 | if (req->rsk_ops->family == AF_INET6) { | 130 | if (req->rsk_ops->family == AF_INET6) { |
158 | const struct ipv6hdr *ip6h = ipv6_hdr(syn); | 131 | const struct ipv6hdr *ip6h = ipv6_hdr(syn); |
159 | struct tcp_fastopen_cookie tmp; | 132 | |
160 | struct in6_addr *buf; | 133 | foc->val[0] = siphash(&ip6h->saddr, |
161 | int i; | 134 | sizeof(ip6h->saddr) + |
162 | 135 | sizeof(ip6h->daddr), | |
163 | crypto_cipher_encrypt_one(tfm, tmp.val, | 136 | (const siphash_key_t *)key); |
164 | (void *)&ip6h->saddr); | ||
165 | buf = &tmp.addr; | ||
166 | for (i = 0; i < 4; i++) | ||
167 | buf->s6_addr32[i] ^= ip6h->daddr.s6_addr32[i]; | ||
168 | crypto_cipher_encrypt_one(tfm, foc->val, (void *)buf); | ||
169 | foc->len = TCP_FASTOPEN_COOKIE_SIZE; | 137 | foc->len = TCP_FASTOPEN_COOKIE_SIZE; |
170 | return true; | 138 | return true; |
171 | } | 139 | } |
@@ -173,11 +141,8 @@ static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req, | |||
173 | return false; | 141 | return false; |
174 | } | 142 | } |
175 | 143 | ||
176 | /* Generate the fastopen cookie by doing aes128 encryption on both | 144 | /* Generate the fastopen cookie by applying SipHash to both the source and |
177 | * the source and destination addresses. Pad 0s for IPv4 or IPv4-mapped-IPv6 | 145 | * destination addresses. |
178 | * addresses. For the longer IPv6 addresses use CBC-MAC. | ||
179 | * | ||
180 | * XXX (TFO) - refactor when TCP_FASTOPEN_COOKIE_SIZE != AES_BLOCK_SIZE. | ||
181 | */ | 146 | */ |
182 | static void tcp_fastopen_cookie_gen(struct sock *sk, | 147 | static void tcp_fastopen_cookie_gen(struct sock *sk, |
183 | struct request_sock *req, | 148 | struct request_sock *req, |
@@ -189,7 +154,7 @@ static void tcp_fastopen_cookie_gen(struct sock *sk, | |||
189 | rcu_read_lock(); | 154 | rcu_read_lock(); |
190 | ctx = tcp_fastopen_get_ctx(sk); | 155 | ctx = tcp_fastopen_get_ctx(sk); |
191 | if (ctx) | 156 | if (ctx) |
192 | __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->tfm[0], foc); | 157 | __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->key[0], foc); |
193 | rcu_read_unlock(); | 158 | rcu_read_unlock(); |
194 | } | 159 | } |
195 | 160 | ||
@@ -253,7 +218,7 @@ static int tcp_fastopen_cookie_gen_check(struct sock *sk, | |||
253 | if (!ctx) | 218 | if (!ctx) |
254 | goto out; | 219 | goto out; |
255 | for (i = 0; i < tcp_fastopen_context_len(ctx); i++) { | 220 | for (i = 0; i < tcp_fastopen_context_len(ctx); i++) { |
256 | __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->tfm[i], foc); | 221 | __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->key[i], foc); |
257 | if (tcp_fastopen_cookie_match(foc, orig)) { | 222 | if (tcp_fastopen_cookie_match(foc, orig)) { |
258 | ret = i + 1; | 223 | ret = i + 1; |
259 | goto out; | 224 | goto out; |