Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vsock/test: Add test for a linear and non-linear skb getting coalesced

Loopback transport can mangle data in rx queue when a linear skb is
followed by a small MSG_ZEROCOPY packet.

To exercise the logic, send out two packets: a weirdly sized one (to ensure
some spare tail room in the skb) and a zerocopy one that's small enough to
fit in the spare room of its predecessor. Then, wait for both to land in
the rx queue, and check the data received. Faulty packets merger manifests
itself by corrupting payload of the later packet.

Signed-off-by: Michal Luczaj <mhal@rbox.co>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Link: https://patch.msgid.link/20260113-vsock-recv-coalescence-v2-2-552b17837cf4@rbox.co
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Michal Luczaj and committed by
Jakub Kicinski
a63e5fe0 0386bd32

+82
+5
tools/testing/vsock/vsock_test.c
··· 2403 2403 .run_client = test_stream_accepted_setsockopt_client, 2404 2404 .run_server = test_stream_accepted_setsockopt_server, 2405 2405 }, 2406 + { 2407 + .name = "SOCK_STREAM virtio MSG_ZEROCOPY coalescence corruption", 2408 + .run_client = test_stream_msgzcopy_mangle_client, 2409 + .run_server = test_stream_msgzcopy_mangle_server, 2410 + }, 2406 2411 {}, 2407 2412 }; 2408 2413
+74
tools/testing/vsock/vsock_test_zerocopy.c
··· 9 9 #include <stdio.h> 10 10 #include <stdlib.h> 11 11 #include <string.h> 12 + #include <sys/ioctl.h> 12 13 #include <sys/mman.h> 13 14 #include <unistd.h> 14 15 #include <poll.h> 15 16 #include <linux/errqueue.h> 16 17 #include <linux/kernel.h> 18 + #include <linux/sockios.h> 19 + #include <linux/time64.h> 17 20 #include <errno.h> 18 21 19 22 #include "control.h" 23 + #include "timeout.h" 20 24 #include "vsock_test_zerocopy.h" 21 25 #include "msg_zerocopy_common.h" 22 26 ··· 358 354 } 359 355 360 356 control_expectln("DONE"); 357 + close(fd); 358 + } 359 + 360 + #define GOOD_COPY_LEN 128 /* net/vmw_vsock/virtio_transport_common.c */ 361 + 362 + void test_stream_msgzcopy_mangle_client(const struct test_opts *opts) 363 + { 364 + char sbuf1[PAGE_SIZE + 1], sbuf2[GOOD_COPY_LEN]; 365 + unsigned long hash; 366 + struct pollfd fds; 367 + int fd, i; 368 + 369 + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); 370 + if (fd < 0) { 371 + perror("connect"); 372 + exit(EXIT_FAILURE); 373 + } 374 + 375 + enable_so_zerocopy_check(fd); 376 + 377 + memset(sbuf1, 'x', sizeof(sbuf1)); 378 + send_buf(fd, sbuf1, sizeof(sbuf1), 0, sizeof(sbuf1)); 379 + 380 + for (i = 0; i < sizeof(sbuf2); i++) 381 + sbuf2[i] = rand() & 0xff; 382 + 383 + send_buf(fd, sbuf2, sizeof(sbuf2), MSG_ZEROCOPY, sizeof(sbuf2)); 384 + 385 + hash = hash_djb2(sbuf2, sizeof(sbuf2)); 386 + control_writeulong(hash); 387 + 388 + fds.fd = fd; 389 + fds.events = 0; 390 + 391 + if (poll(&fds, 1, TIMEOUT * MSEC_PER_SEC) != 1 || 392 + !(fds.revents & POLLERR)) { 393 + perror("poll"); 394 + exit(EXIT_FAILURE); 395 + } 396 + 397 + close(fd); 398 + } 399 + 400 + void test_stream_msgzcopy_mangle_server(const struct test_opts *opts) 401 + { 402 + unsigned long local_hash, remote_hash; 403 + char rbuf[PAGE_SIZE + 1]; 404 + int fd; 405 + 406 + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); 407 + if (fd < 0) { 408 + perror("accept"); 409 + exit(EXIT_FAILURE); 410 + } 411 + 412 + /* Wait, don't race the (buggy) skbs coalescence. */ 413 + vsock_ioctl_int(fd, SIOCINQ, PAGE_SIZE + 1 + GOOD_COPY_LEN); 414 + 415 + /* Discard the first packet. */ 416 + recv_buf(fd, rbuf, PAGE_SIZE + 1, 0, PAGE_SIZE + 1); 417 + 418 + recv_buf(fd, rbuf, GOOD_COPY_LEN, 0, GOOD_COPY_LEN); 419 + remote_hash = control_readulong(); 420 + local_hash = hash_djb2(rbuf, GOOD_COPY_LEN); 421 + 422 + if (local_hash != remote_hash) { 423 + fprintf(stderr, "Data received corrupted\n"); 424 + exit(EXIT_FAILURE); 425 + } 426 + 361 427 close(fd); 362 428 }
+3
tools/testing/vsock/vsock_test_zerocopy.h
··· 12 12 void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts); 13 13 void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts); 14 14 15 + void test_stream_msgzcopy_mangle_client(const struct test_opts *opts); 16 + void test_stream_msgzcopy_mangle_server(const struct test_opts *opts); 17 + 15 18 #endif /* VSOCK_TEST_ZEROCOPY_H */