xref: /linux/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c (revision 5949a7cf11e685dd171e33586c272dfe673310b6)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Cloudflare
3 /*
4  * Tests for sockmap/sockhash holding kTLS sockets.
5  */
6 #include <error.h>
7 #include <netinet/tcp.h>
8 #include <linux/tls.h>
9 #include "test_progs.h"
10 #include "sockmap_helpers.h"
11 #include "test_skmsg_load_helpers.skel.h"
12 
13 #define MAX_TEST_NAME 80
14 #define TCP_ULP 31
15 
16 static int init_ktls_pairs(int c, int p)
17 {
18 	int err;
19 	struct tls12_crypto_info_aes_gcm_128 crypto_rx;
20 	struct tls12_crypto_info_aes_gcm_128 crypto_tx;
21 
22 	err = setsockopt(c, IPPROTO_TCP, TCP_ULP, "tls", strlen("tls"));
23 	if (!ASSERT_OK(err, "setsockopt(TCP_ULP)"))
24 		goto out;
25 
26 	err = setsockopt(p, IPPROTO_TCP, TCP_ULP, "tls", strlen("tls"));
27 	if (!ASSERT_OK(err, "setsockopt(TCP_ULP)"))
28 		goto out;
29 
30 	memset(&crypto_rx, 0, sizeof(crypto_rx));
31 	memset(&crypto_tx, 0, sizeof(crypto_tx));
32 	crypto_rx.info.version = TLS_1_2_VERSION;
33 	crypto_tx.info.version = TLS_1_2_VERSION;
34 	crypto_rx.info.cipher_type = TLS_CIPHER_AES_GCM_128;
35 	crypto_tx.info.cipher_type = TLS_CIPHER_AES_GCM_128;
36 
37 	err = setsockopt(c, SOL_TLS, TLS_TX, &crypto_tx, sizeof(crypto_tx));
38 	if (!ASSERT_OK(err, "setsockopt(TLS_TX)"))
39 		goto out;
40 
41 	err = setsockopt(p, SOL_TLS, TLS_RX, &crypto_rx, sizeof(crypto_rx));
42 	if (!ASSERT_OK(err, "setsockopt(TLS_RX)"))
43 		goto out;
44 	return 0;
45 out:
46 	return -1;
47 }
48 
49 static int create_ktls_pairs(int family, int sotype, int *c, int *p)
50 {
51 	int err;
52 
53 	err = create_pair(family, sotype, c, p);
54 	if (!ASSERT_OK(err, "create_pair()"))
55 		return -1;
56 
57 	err = init_ktls_pairs(*c, *p);
58 	if (!ASSERT_OK(err, "init_ktls_pairs(c, p)"))
59 		return -1;
60 	return 0;
61 }
62 
63 static void test_sockmap_ktls_update_fails_when_sock_has_ulp(int family, int map)
64 {
65 	struct sockaddr_storage addr = {};
66 	socklen_t len = sizeof(addr);
67 	struct sockaddr_in6 *v6;
68 	struct sockaddr_in *v4;
69 	int err, s, zero = 0;
70 
71 	switch (family) {
72 	case AF_INET:
73 		v4 = (struct sockaddr_in *)&addr;
74 		v4->sin_family = AF_INET;
75 		break;
76 	case AF_INET6:
77 		v6 = (struct sockaddr_in6 *)&addr;
78 		v6->sin6_family = AF_INET6;
79 		break;
80 	default:
81 		PRINT_FAIL("unsupported socket family %d", family);
82 		return;
83 	}
84 
85 	s = socket(family, SOCK_STREAM, 0);
86 	if (!ASSERT_GE(s, 0, "socket"))
87 		return;
88 
89 	err = bind(s, (struct sockaddr *)&addr, len);
90 	if (!ASSERT_OK(err, "bind"))
91 		goto close;
92 
93 	err = getsockname(s, (struct sockaddr *)&addr, &len);
94 	if (!ASSERT_OK(err, "getsockname"))
95 		goto close;
96 
97 	err = connect(s, (struct sockaddr *)&addr, len);
98 	if (!ASSERT_OK(err, "connect"))
99 		goto close;
100 
101 	/* save sk->sk_prot and set it to tls_prots */
102 	err = setsockopt(s, IPPROTO_TCP, TCP_ULP, "tls", strlen("tls"));
103 	if (!ASSERT_OK(err, "setsockopt(TCP_ULP)"))
104 		goto close;
105 
106 	/* sockmap update should not affect saved sk_prot */
107 	err = bpf_map_update_elem(map, &zero, &s, BPF_ANY);
108 	if (!ASSERT_ERR(err, "sockmap update elem"))
109 		goto close;
110 
111 	/* call sk->sk_prot->setsockopt to dispatch to saved sk_prot */
112 	err = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &zero, sizeof(zero));
113 	ASSERT_OK(err, "setsockopt(TCP_NODELAY)");
114 
115 close:
116 	close(s);
117 }
118 
119 static void test_sockmap_ktls_enable_fails_when_in_sockmap(int family, int map)
120 {
121 	struct tls12_crypto_info_aes_gcm_128 crypto = {
122 		.info = {
123 			.version     = TLS_1_2_VERSION,
124 			.cipher_type = TLS_CIPHER_AES_GCM_128,
125 		},
126 	};
127 	struct sockaddr_storage addr = {};
128 	socklen_t len = sizeof(addr);
129 	struct sockaddr_in6 *v6;
130 	struct sockaddr_in *v4;
131 	int err, s, zero = 0;
132 
133 	switch (family) {
134 	case AF_INET:
135 		v4 = (struct sockaddr_in *)&addr;
136 		v4->sin_family = AF_INET;
137 		break;
138 	case AF_INET6:
139 		v6 = (struct sockaddr_in6 *)&addr;
140 		v6->sin6_family = AF_INET6;
141 		break;
142 	default:
143 		PRINT_FAIL("unsupported socket family %d", family);
144 		return;
145 	}
146 
147 	s = socket(family, SOCK_STREAM, 0);
148 	if (!ASSERT_GE(s, 0, "socket"))
149 		return;
150 
151 	err = bind(s, (struct sockaddr *)&addr, len);
152 	if (!ASSERT_OK(err, "bind"))
153 		goto close;
154 
155 	err = getsockname(s, (struct sockaddr *)&addr, &len);
156 	if (!ASSERT_OK(err, "getsockname"))
157 		goto close;
158 
159 	err = connect(s, (struct sockaddr *)&addr, len);
160 	if (!ASSERT_OK(err, "connect"))
161 		goto close;
162 
163 	/* Add the socket to the sockmap, attaching a psock. */
164 	err = bpf_map_update_elem(map, &zero, &s, BPF_ANY);
165 	if (!ASSERT_OK(err, "sockmap update elem"))
166 		goto close;
167 
168 	/* Installing the TLS ULP is allowed, it does not touch the datapath. */
169 	err = setsockopt(s, IPPROTO_TCP, TCP_ULP, "tls", strlen("tls"));
170 	if (!ASSERT_OK(err, "setsockopt(TCP_ULP)"))
171 		goto close;
172 
173 	/* Enabling the TLS crypto datapath must be rejected. */
174 	err = setsockopt(s, SOL_TLS, TLS_TX, &crypto, sizeof(crypto));
175 	ASSERT_ERR(err, "setsockopt(TLS_TX)");
176 
177 close:
178 	close(s);
179 }
180 
181 static const char *fmt_test_name(const char *subtest_name, int family,
182 				 enum bpf_map_type map_type)
183 {
184 	const char *map_type_str = BPF_MAP_TYPE_SOCKMAP ? "SOCKMAP" : "SOCKHASH";
185 	const char *family_str = AF_INET ? "IPv4" : "IPv6";
186 	static char test_name[MAX_TEST_NAME];
187 
188 	snprintf(test_name, MAX_TEST_NAME,
189 		 "sockmap_ktls %s %s %s",
190 		 subtest_name, family_str, map_type_str);
191 
192 	return test_name;
193 }
194 
195 static void test_sockmap_ktls_offload(int family, int sotype)
196 {
197 	int err;
198 	int c = 0, p = 0, sent, recvd;
199 	char msg[12] = "hello world\0";
200 	char rcv[13];
201 
202 	err = create_ktls_pairs(family, sotype, &c, &p);
203 	if (!ASSERT_OK(err, "create_ktls_pairs()"))
204 		goto out;
205 
206 	sent = send(c, msg, sizeof(msg), 0);
207 	if (!ASSERT_OK(err, "send(msg)"))
208 		goto out;
209 
210 	recvd = recv(p, rcv, sizeof(rcv), 0);
211 	if (!ASSERT_OK(err, "recv(msg)") ||
212 	    !ASSERT_EQ(recvd, sent, "length mismatch"))
213 		goto out;
214 
215 	ASSERT_OK(memcmp(msg, rcv, sizeof(msg)), "data mismatch");
216 
217 out:
218 	if (c)
219 		close(c);
220 	if (p)
221 		close(p);
222 }
223 
224 static void run_tests(int family, enum bpf_map_type map_type)
225 {
226 	int map;
227 
228 	map = bpf_map_create(map_type, NULL, sizeof(int), sizeof(int), 1, NULL);
229 	if (!ASSERT_GE(map, 0, "bpf_map_create"))
230 		return;
231 
232 	if (test__start_subtest(fmt_test_name("update_fails_when_sock_has_ulp", family, map_type)))
233 		test_sockmap_ktls_update_fails_when_sock_has_ulp(family, map);
234 
235 	if (test__start_subtest(fmt_test_name("enable_fails_when_in_sockmap", family, map_type)))
236 		test_sockmap_ktls_enable_fails_when_in_sockmap(family, map);
237 
238 	close(map);
239 }
240 
241 static void run_ktls_test(int family, int sotype)
242 {
243 	if (test__start_subtest("tls simple offload"))
244 		test_sockmap_ktls_offload(family, sotype);
245 }
246 
247 void test_sockmap_ktls(void)
248 {
249 	run_tests(AF_INET, BPF_MAP_TYPE_SOCKMAP);
250 	run_tests(AF_INET, BPF_MAP_TYPE_SOCKHASH);
251 	run_tests(AF_INET6, BPF_MAP_TYPE_SOCKMAP);
252 	run_tests(AF_INET6, BPF_MAP_TYPE_SOCKHASH);
253 	run_ktls_test(AF_INET, SOCK_STREAM);
254 	run_ktls_test(AF_INET6, SOCK_STREAM);
255 }
256