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