xref: /xnu-11417.121.6/tests/skywalk/skt_mangle.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1 /*
2  * Copyright (c) 2016-2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdbool.h>
34 #include <pthread.h>
35 #include <unistd.h>
36 #include <uuid/uuid.h>
37 #include <sys/select.h>
38 #include <poll.h>
39 #include <time.h>
40 #include <sys/event.h>
41 #include <sys/sysctl.h>
42 #include <err.h>
43 #include <sysexits.h>
44 #include "skywalk_test_driver.h"
45 #include "skywalk_test_common.h"
46 #include "skywalk_test_utils.h"
47 
48 struct context {
49 	uuid_t nexus_uuid;
50 	int argc;
51 	char **argv;
52 	int test_selector;
53 	struct stage_ctx stage;
54 };
55 
56 enum mangle_test_selector {
57 	SKT_CHANGE_LEN,
58 	SKT_BIG_LEN,
59 };
60 
61 enum mangle_stage {
62 	SKT_INIT=0,
63 	SKT_TX_TURN,
64 	SKT_RX_TURN,
65 };
66 
67 struct internalize_ctx {
68 	int utun_fd;
69 	struct sktc_nexus_handles handles;
70 	channel_port port;
71 	struct sktu_flow *flow;
72 	struct in_addr our_ip;
73 	struct in_addr dst_ip;
74 };
75 
76 static void
skt_mangle_init(void)77 skt_mangle_init(void)
78 {
79 	uint32_t disable_panic_on_sync_err = 1;
80 	struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();
81 
82 	sysctlbyname("kern.skywalk.disable_panic_on_sync_err",
83 	    NULL, 0, &disable_panic_on_sync_err,
84 	    sizeof(disable_panic_on_sync_err));
85 
86 	strncpy((char *)attr.name, "skywalk_test_mangle_upipe",
87 	    sizeof(nexus_name_t) - 1);
88 	attr.type = NEXUS_TYPE_USER_PIPE;
89 	attr.ntxrings = 1;
90 	attr.nrxrings = 1;
91 	attr.ntxslots = 64;
92 	attr.nrxslots = 64;
93 	attr.anonymous = 1;
94 
95 	sktc_setup_nexus(&attr);
96 }
97 
98 static void
skt_mangle_fini(void)99 skt_mangle_fini(void)
100 {
101 	uint32_t disable_panic_on_sync_err = 0;
102 
103 	sysctlbyname("kern.skywalk.disable_panic_on_sync_err",
104 	    NULL, 0, &disable_panic_on_sync_err,
105 	    sizeof(disable_panic_on_sync_err));
106 
107 	sktc_cleanup_nexus();
108 }
109 
110 static void *
skt_mangle_verify_internalize_metadata(void * _ctx)111 skt_mangle_verify_internalize_metadata(void *_ctx)
112 {
113 	struct internalize_ctx *ctx = _ctx;
114 	uint16_t sport;
115 	uint16_t dport;
116 
117 	sport = ntohs(ctx->flow->nfr.nfr_saddr.sin.sin_port);
118 	dport = ntohs(ctx->flow->nfr.nfr_daddr.sin.sin_port);
119 
120 	my_payload tx_payload;
121 	bzero(&tx_payload, sizeof(tx_payload));
122 	tx_payload.packet_number = 0;
123 	strlcpy(tx_payload.data, "udp_flow_send", sizeof(tx_payload.data));
124 
125 	struct sktu_frame *tx_frame;
126 	sktu_create_udp_frames(&tx_frame, 1, IPVERSION,
127 	    &ctx->our_ip, &ctx->dst_ip, sport, dport, &tx_payload,
128 	    sizeof(tx_payload), 1500, CSUM_OFFLOAD);
129 	uuid_copy(tx_frame->flow_uuid, ctx->flow->nfr.nfr_flow_uuid);
130 
131 	packet_t pkt = sktu_channel_port_frame_to_pkt(&ctx->port, tx_frame);
132 
133 	uint32_t frame_length = os_packet_get_data_length(pkt);
134 	/* stuff_off to be greater than actual frame length */
135 	os_packet_set_inet_checksum(pkt, PACKET_CSUM_PARTIAL, sizeof(struct ip),
136 	    frame_length + 1);
137 
138 	struct __user_quantum *uqum = SK_PTR_ADDR_UQUM(pkt);
139 	/* pkt_length to be greater than stuff_off + sizeof(csum) */
140 	uqum->qum_len = frame_length + 3;
141 
142 	sktu_channel_port_tx_burst_pkt(&ctx->port, &pkt, 1);
143 	/*
144 	 * With the changes in rdar://problem/72632756, TX thread will crash
145 	 * after writing an invalid packet.
146 	 */
147 
148 	sktu_frame_free(tx_frame);
149 	return 0;
150 }
151 
152 static void *
skt_mangle_rx(void * ctx_)153 skt_mangle_rx(void *ctx_)
154 {
155 	struct context *ctx = (struct context *)ctx_;
156 	channel_t channel;
157 	channel_ring_t rxring;
158 	ring_dir_t ring_dir = CHANNEL_DIR_RX;
159 	ring_id_t ring_id = CHANNEL_RING_ID_ANY;
160 	uint32_t port = 0;
161 	int kq_fd;
162 	int error;
163 
164 	assert(ctx->stage.test_stage == SKT_INIT);
165 
166 	/* Initialize kqueue */
167 	kq_fd = kqueue();
168 	assert(kq_fd >= 0);
169 
170 	/* Initialize channel */
171 	channel = sktu_channel_create_extended(
172 		ctx->nexus_uuid,
173 		port, ring_dir, ring_id,
174 		NULL,
175 		-1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
176 	assert(channel != NULL);
177 
178 	ring_id = os_channel_ring_id(channel, CHANNEL_FIRST_RX_RING);
179 	rxring = os_channel_rx_ring(channel, ring_id);
180 	assert(rxring);
181 
182 	/* Don't care about watermark, but set units to 'bytes' */
183 	set_watermark(channel, false, CHANNEL_THRESHOLD_UNIT_BYTES, 1);
184 
185 	switch (ctx->test_selector) {
186 	case SKT_CHANGE_LEN:
187 		/* Let TX send one slot with 10 bytes */
188 		test_stage_change(&ctx->stage, SKT_TX_TURN);
189 		test_stage_wait(&ctx->stage, SKT_RX_TURN);
190 
191 		error = os_channel_sync(channel, CHANNEL_SYNC_RX);
192 		SKTC_ASSERT_ERR(!error);
193 
194 		/* Receive that slot and mess with its length */
195 		channel_slot_t slot;
196 		struct slot_prop prop;
197 		slot = os_channel_get_next_slot(rxring, NULL, &prop);
198 
199 		/*
200 		 * Try to trick the kernel into thinking there are 4 bytes
201 		 * less than there really are
202 		 */
203 		assert(slot);
204 		prop.sp_len = 6;
205 		os_channel_set_slot_properties(rxring, slot, &prop);
206 
207 		error = os_channel_advance_slot(rxring, slot);
208 		SKTC_ASSERT_ERR(!error);
209 
210 		error = os_channel_sync(channel, CHANNEL_SYNC_RX);
211 		SKTC_ASSERT_ERR(!error);
212 
213 		test_stage_change(&ctx->stage, SKT_TX_TURN);
214 
215 		/*
216 		 * Get the kernel view of how many bytes are in the ring.
217 		 * should be the original count.
218 		 */
219 		error = wait_on_fd(kq_fd, EVFILT_READ, channel, 0, TIMEOUT_FAIL);
220 		SKTC_ASSERT_ERR(error == 10);
221 		break;
222 
223 	case SKT_BIG_LEN:
224 		/* Let TX try to send an unreasonably large slot */
225 		test_stage_change(&ctx->stage, SKT_TX_TURN);
226 
227 		/*
228 		 * With the changes in rdar://problem/72632756,
229 		 * TX side will crash after writing an invalid
230 		 * length packet.
231 		 * Hence the below code is commented out.
232 		 */
233 #if 0
234 		test_stage_wait(&ctx->stage, SKT_RX_TURN);
235 
236 		/* Guarantee the data in the ring is less than what was requested */
237 		error = wait_on_fd(kq_fd, EVFILT_READ, channel, 0, TIMEOUT_FAIL);
238 		SKTC_ASSERT_ERR(error == 214);  /* 131 + 83 */
239 #endif
240 
241 		break;
242 	}
243 
244 	return 0;
245 }
246 
247 static void *
skt_mangle_tx(void * ctx_)248 skt_mangle_tx(void *ctx_)
249 {
250 	struct context *ctx = (struct context *)ctx_;
251 	channel_t channel;
252 	channel_ring_t txring;
253 	ring_dir_t ring_dir = CHANNEL_DIR_TX;
254 	ring_id_t ring_id = CHANNEL_RING_ID_ANY;
255 	uint32_t port = 1;
256 	int error;
257 	int kq_fd;
258 
259 	kq_fd = kqueue();
260 	assert(kq_fd >= 0);
261 
262 	channel = sktu_channel_create_extended(
263 		ctx->nexus_uuid,
264 		port, ring_dir, ring_id,
265 		NULL,
266 		-1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
267 	assert(channel != NULL);
268 
269 	ring_id = os_channel_ring_id(channel, CHANNEL_FIRST_TX_RING);
270 	txring = os_channel_tx_ring(channel, ring_id);
271 	assert(txring);
272 
273 	switch (ctx->test_selector) {
274 	case SKT_CHANGE_LEN:
275 		/* Wait for RX to initialize */
276 		test_stage_wait(&ctx->stage, SKT_TX_TURN);
277 
278 		/* Send 10 bytes */
279 		send_bytes(txring, 10);
280 		error = os_channel_sync(channel, CHANNEL_SYNC_TX);
281 		SKTC_ASSERT_ERR(error == 0);
282 		test_stage_change(&ctx->stage, SKT_RX_TURN);
283 		test_stage_wait(&ctx->stage, SKT_TX_TURN);
284 
285 		send_bytes(txring, 10);
286 		error = os_channel_sync(channel, CHANNEL_SYNC_TX);
287 		SKTC_ASSERT_ERR(error == 0);
288 		break;
289 
290 	case SKT_BIG_LEN: {
291 		/* Wait for RX to initialize */
292 		test_stage_wait(&ctx->stage, SKT_TX_TURN);
293 
294 		/*
295 		 * Write 3 slots; the one with an invalid length should
296 		 * be truncated by kernel (to 0 bytes), but not the
297 		 * other two.
298 		 */
299 		slot_prop_t prop;
300 		channel_slot_t slot = os_channel_get_next_slot(txring, NULL, &prop);
301 		assert(slot);
302 
303 		/* Request the largest buffer the kernel structures will allow */
304 		prop.sp_len = 65535;
305 		os_channel_set_slot_properties(txring, slot, &prop);
306 
307 		slot = os_channel_get_next_slot(txring, slot, &prop);
308 		assert(slot);
309 		prop.sp_len = 131;
310 		os_channel_set_slot_properties(txring, slot, &prop);
311 
312 		slot = os_channel_get_next_slot(txring, slot, &prop);
313 		assert(slot);
314 		prop.sp_len = 83;
315 		os_channel_set_slot_properties(txring, slot, &prop);
316 
317 		error = os_channel_advance_slot(txring, slot);
318 		SKTC_ASSERT_ERR(!error);
319 
320 		error = os_channel_sync(channel, CHANNEL_SYNC_TX);
321 		/* Expect failure (and a process crash) here */
322 
323 		/*
324 		 * Sanity checks to localize failures, in case the crash
325 		 * doesn't succeed:
326 		 */
327 		SKTC_ASSERT_ERR(error);
328 		SKTC_ASSERT_ERR(errno == EFAULT);
329 
330 		//test_stage_change(&ctx->stage, SKT_RX_TURN);
331 		break;
332 	}
333 	}
334 
335 	return 0;
336 }
337 
338 static int
skt_mangle_main(int argc,char * argv[],int test_selector)339 skt_mangle_main(int argc, char *argv[], int test_selector)
340 {
341 	pthread_t rx_thread, tx_thread;
342 	struct context ctx;
343 	int error;
344 
345 	test_stage_init(&ctx.stage, SKT_INIT);
346 	ctx.argc = argc;
347 	ctx.argv = argv;
348 	ctx.test_selector = test_selector;
349 
350 	error = uuid_parse(argv[3], ctx.nexus_uuid);
351 	SKTC_ASSERT_ERR(!error);
352 
353 	error = pthread_create(&rx_thread, NULL, &skt_mangle_rx, &ctx);
354 	SKTC_ASSERT_ERR(!error);
355 	error = pthread_create(&tx_thread, NULL, &skt_mangle_tx, &ctx);
356 	SKTC_ASSERT_ERR(!error);
357 
358 	pthread_join(rx_thread, NULL);
359 	pthread_join(tx_thread, NULL);
360 
361 	test_stage_destroy(&ctx.stage);
362 
363 	return 0;
364 }
365 
366 static int
skt_change_len_main(int argc,char * argv[])367 skt_change_len_main(int argc, char *argv[])
368 {
369 	return skt_mangle_main(argc, argv, SKT_CHANGE_LEN);
370 }
371 
372 static int
skt_big_len_main(int argc,char * argv[])373 skt_big_len_main(int argc, char *argv[])
374 {
375 	return skt_mangle_main(argc, argv, SKT_BIG_LEN);
376 }
377 
378 static int
skt_mangle_verify_internalize_metadata_main(int argc,char * argv[])379 skt_mangle_verify_internalize_metadata_main(int argc, char *argv[])
380 {
381 #pragma unused (argc, argv)
382 	char *utun_addr_str = "10.0.250.1";
383 	char *peer_addr_str = "10.0.250.2";
384 	char *broad_addr_str = "10.0.250.255";
385 	char utun_ifname[IFNAMSIZ + 1];
386 	struct internalize_ctx ctx;
387 	struct in_addr broad_ip;
388 	struct in_addr mask;
389 	uint16_t sport = 0;
390 	uint16_t dport = 4321;
391 	int error;
392 
393 	inet_pton(AF_INET, utun_addr_str, &ctx.our_ip);
394 	inet_pton(AF_INET, peer_addr_str, &ctx.dst_ip);
395 	inet_pton(AF_INET, broad_addr_str, &broad_ip);
396 	mask = sktc_make_in_addr(IN_CLASSC_NET);
397 
398 	ctx.utun_fd = sktu_create_interface(SKTU_IFT_UTUN,
399 	    SKTU_IFF_ENABLE_NETIF | SKTU_IFF_NO_ATTACH_FSW);
400 	sktu_get_interface_name(SKTU_IFT_UTUN, ctx.utun_fd, utun_ifname);
401 
402 	if (sktc_ifnet_add_addr(utun_ifname, &ctx.our_ip, &mask, &broad_ip) !=
403 	    0) {
404 		err(EX_OSERR, "Failed to add address for %s", utun_ifname);
405 	}
406 
407 	if (sktc_ifnet_add_scoped_default_route(utun_ifname, ctx.our_ip) != 0) {
408 		err(EX_OSERR, "Failed to add default route for %s\n",
409 		    utun_ifname);
410 	}
411 
412 	bzero(&ctx.handles, sizeof(ctx.handles));
413 	strlcpy(ctx.handles.netif_ifname, utun_ifname,
414 	    sizeof(ctx.handles.netif_ifname));
415 	ctx.handles.netif_addr = ctx.our_ip;
416 	ctx.handles.netif_mask = mask;
417 	sktc_create_flowswitch_no_address(&ctx.handles, -1, -1, -1, -1, 0);
418 
419 	error =
420 	    os_nexus_controller_bind_provider_instance(ctx.handles.controller,
421 	    ctx.handles.fsw_nx_uuid, 3, getpid(), NULL, NULL, 0,
422 	    NEXUS_BIND_PID);
423 	SKTC_ASSERT_ERR(error == 0);
424 
425 	sktu_channel_port_init(&ctx.port, ctx.handles.fsw_nx_uuid, 3, true,
426 	    false, false);
427 	assert(ctx.port.chan != NULL);
428 	assert(ctx.port.user_packet_pool);
429 
430 	ctx.flow = sktu_create_nexus_flow(&ctx.handles, AF_INET, &ctx.our_ip,
431 	    &ctx.dst_ip, IPPROTO_UDP, sport, dport);
432 
433 	pthread_t tx_thread;
434 
435 	error = pthread_create(&tx_thread, NULL,
436 	    &skt_mangle_verify_internalize_metadata, &ctx);
437 	SKTC_ASSERT_ERR(!error);
438 	pthread_join(tx_thread, NULL);
439 
440 	sktu_destroy_nexus_flow(ctx.flow);
441 	sktc_cleanup_flowswitch(&ctx.handles);
442 	close(ctx.utun_fd);
443 	return 0;
444 }
445 
446 struct skywalk_test skt_change_len = {
447 	"change_len", "tests kernel resilience to modified slot lengths",
448 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE |
449 	SK_FEATURE_DEV_OR_DEBUG,
450 	skt_change_len_main, SKTC_GENERIC_UPIPE_ARGV,
451 	skt_mangle_init, skt_mangle_fini,
452 };
453 
454 struct skywalk_test skt_big_len = {
455 	"big_len", "tests unrealistically large slot lengths",
456 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE |
457 	SK_FEATURE_DEV_OR_DEBUG,
458 	skt_big_len_main, SKTC_GENERIC_UPIPE_ARGV,
459 	skt_mangle_init, skt_mangle_fini, (SIGABRT << 24), 0,
460 };
461 
462 struct skywalk_test skt_internalizemetdata = {
463 	.skt_testname = "internalizemetadata",
464 	.skt_testdesc = "Internalize packet metadata verification",
465 	.skt_required_features = SK_FEATURE_SKYWALK |
466     SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NEXUS_NETIF | SK_FEATURE_NETNS,
467 	.skt_main = skt_mangle_verify_internalize_metadata_main,
468 	.skt_expected_exception_code = (SIGABRT << 24),
469 	.skt_expected_exception_code_ignore = 0,
470 };
471