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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'vsock-virtio-fix-data-loss-disclosure-due-to-joining-of-non-linear-skb'

Michal Luczaj says:

====================
vsock/virtio: Fix data loss/disclosure due to joining of non-linear skb

Loopback transport coalesces some skbs too eagerly. Handling a zerocopy
(non-linear) skb as a linear one leads to skb data loss and kernel memory
disclosure.

Plug the loss/leak by allowing only linear skb join. Provide a test.
====================

Link: https://patch.msgid.link/20260113-vsock-recv-coalescence-v2-0-552b17837cf4@rbox.co
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+86 -2
+4 -2
net/vmw_vsock/virtio_transport_common.c
··· 1359 1359 1360 1360 /* Try to copy small packets into the buffer of last packet queued, 1361 1361 * to avoid wasting memory queueing the entire buffer with a small 1362 - * payload. 1362 + * payload. Skip non-linear (e.g. zerocopy) skbs; these carry payload 1363 + * in skb_shinfo. 1363 1364 */ 1364 - if (len <= GOOD_COPY_LEN && !skb_queue_empty(&vvs->rx_queue)) { 1365 + if (len <= GOOD_COPY_LEN && !skb_queue_empty(&vvs->rx_queue) && 1366 + !skb_is_nonlinear(skb)) { 1365 1367 struct virtio_vsock_hdr *last_hdr; 1366 1368 struct sk_buff *last_skb; 1367 1369
+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 */