Loading net/vmw_vsock/virtio_transport_common.c +13 −16 Original line number Diff line number Diff line Loading @@ -241,21 +241,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, } static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *skb) u32 len) { if (vvs->rx_bytes + skb->len > vvs->buf_alloc) if (vvs->rx_bytes + len > vvs->buf_alloc) return false; vvs->rx_bytes += skb->len; vvs->rx_bytes += len; return true; } static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *skb) u32 len) { int len; len = skb_headroom(skb) - sizeof(struct virtio_vsock_hdr) - skb->len; vvs->rx_bytes -= len; vvs->fwd_cnt += len; } Loading Loading @@ -367,7 +364,7 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, spin_lock_bh(&vvs->rx_lock); while (total < len && !skb_queue_empty(&vvs->rx_queue)) { skb = __skb_dequeue(&vvs->rx_queue); skb = skb_peek(&vvs->rx_queue); bytes = len - total; if (bytes > skb->len) Loading @@ -388,10 +385,11 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, skb_pull(skb, bytes); if (skb->len == 0) { virtio_transport_dec_rx_pkt(vvs, skb); u32 pkt_len = le32_to_cpu(virtio_vsock_hdr(skb)->len); virtio_transport_dec_rx_pkt(vvs, pkt_len); __skb_unlink(skb, &vvs->rx_queue); consume_skb(skb); } else { __skb_queue_head(&vvs->rx_queue, skb); } } Loading Loading @@ -437,17 +435,17 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, while (!msg_ready) { struct virtio_vsock_hdr *hdr; size_t pkt_len; skb = __skb_dequeue(&vvs->rx_queue); if (!skb) break; hdr = virtio_vsock_hdr(skb); pkt_len = (size_t)le32_to_cpu(hdr->len); if (dequeued_len >= 0) { size_t pkt_len; size_t bytes_to_copy; pkt_len = (size_t)le32_to_cpu(hdr->len); bytes_to_copy = min(user_buf_len, pkt_len); if (bytes_to_copy) { Loading @@ -466,7 +464,6 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, dequeued_len = err; } else { user_buf_len -= bytes_to_copy; skb_pull(skb, bytes_to_copy); } spin_lock_bh(&vvs->rx_lock); Loading @@ -484,7 +481,7 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, msg->msg_flags |= MSG_EOR; } virtio_transport_dec_rx_pkt(vvs, skb); virtio_transport_dec_rx_pkt(vvs, pkt_len); kfree_skb(skb); } Loading Loading @@ -1040,7 +1037,7 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk, spin_lock_bh(&vvs->rx_lock); can_enqueue = virtio_transport_inc_rx_pkt(vvs, skb); can_enqueue = virtio_transport_inc_rx_pkt(vvs, len); if (!can_enqueue) { free_pkt = true; goto out; Loading tools/testing/vsock/vsock_test.c +118 −0 Original line number Diff line number Diff line Loading @@ -860,6 +860,114 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) close(fd); } #define INV_BUF_TEST_DATA_LEN 512 static void test_inv_buf_client(const struct test_opts *opts, bool stream) { unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; ssize_t ret; int fd; if (stream) fd = vsock_stream_connect(opts->peer_cid, 1234); else fd = vsock_seqpacket_connect(opts->peer_cid, 1234); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); } control_expectln("SENDDONE"); /* Use invalid buffer here. */ ret = recv(fd, NULL, sizeof(data), 0); if (ret != -1) { fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); exit(EXIT_FAILURE); } if (errno != ENOMEM) { fprintf(stderr, "unexpected recv(2) errno %d\n", errno); exit(EXIT_FAILURE); } ret = recv(fd, data, sizeof(data), MSG_DONTWAIT); if (stream) { /* For SOCK_STREAM we must continue reading. */ if (ret != sizeof(data)) { fprintf(stderr, "expected recv(2) success, got %zi\n", ret); exit(EXIT_FAILURE); } /* Don't check errno in case of success. */ } else { /* For SOCK_SEQPACKET socket's queue must be empty. */ if (ret != -1) { fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); exit(EXIT_FAILURE); } if (errno != EAGAIN) { fprintf(stderr, "unexpected recv(2) errno %d\n", errno); exit(EXIT_FAILURE); } } control_writeln("DONE"); close(fd); } static void test_inv_buf_server(const struct test_opts *opts, bool stream) { unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; ssize_t res; int fd; if (stream) fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); else fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); } res = send(fd, data, sizeof(data), 0); if (res != sizeof(data)) { fprintf(stderr, "unexpected send(2) result %zi\n", res); exit(EXIT_FAILURE); } control_writeln("SENDDONE"); control_expectln("DONE"); close(fd); } static void test_stream_inv_buf_client(const struct test_opts *opts) { test_inv_buf_client(opts, true); } static void test_stream_inv_buf_server(const struct test_opts *opts) { test_inv_buf_server(opts, true); } static void test_seqpacket_inv_buf_client(const struct test_opts *opts) { test_inv_buf_client(opts, false); } static void test_seqpacket_inv_buf_server(const struct test_opts *opts) { test_inv_buf_server(opts, false); } static struct test_case test_cases[] = { { .name = "SOCK_STREAM connection reset", Loading Loading @@ -920,6 +1028,16 @@ static struct test_case test_cases[] = { .run_client = test_seqpacket_bigmsg_client, .run_server = test_seqpacket_bigmsg_server, }, { .name = "SOCK_STREAM test invalid buffer", .run_client = test_stream_inv_buf_client, .run_server = test_stream_inv_buf_server, }, { .name = "SOCK_SEQPACKET test invalid buffer", .run_client = test_seqpacket_inv_buf_client, .run_server = test_seqpacket_inv_buf_server, }, {}, }; Loading Loading
net/vmw_vsock/virtio_transport_common.c +13 −16 Original line number Diff line number Diff line Loading @@ -241,21 +241,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, } static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *skb) u32 len) { if (vvs->rx_bytes + skb->len > vvs->buf_alloc) if (vvs->rx_bytes + len > vvs->buf_alloc) return false; vvs->rx_bytes += skb->len; vvs->rx_bytes += len; return true; } static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *skb) u32 len) { int len; len = skb_headroom(skb) - sizeof(struct virtio_vsock_hdr) - skb->len; vvs->rx_bytes -= len; vvs->fwd_cnt += len; } Loading Loading @@ -367,7 +364,7 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, spin_lock_bh(&vvs->rx_lock); while (total < len && !skb_queue_empty(&vvs->rx_queue)) { skb = __skb_dequeue(&vvs->rx_queue); skb = skb_peek(&vvs->rx_queue); bytes = len - total; if (bytes > skb->len) Loading @@ -388,10 +385,11 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, skb_pull(skb, bytes); if (skb->len == 0) { virtio_transport_dec_rx_pkt(vvs, skb); u32 pkt_len = le32_to_cpu(virtio_vsock_hdr(skb)->len); virtio_transport_dec_rx_pkt(vvs, pkt_len); __skb_unlink(skb, &vvs->rx_queue); consume_skb(skb); } else { __skb_queue_head(&vvs->rx_queue, skb); } } Loading Loading @@ -437,17 +435,17 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, while (!msg_ready) { struct virtio_vsock_hdr *hdr; size_t pkt_len; skb = __skb_dequeue(&vvs->rx_queue); if (!skb) break; hdr = virtio_vsock_hdr(skb); pkt_len = (size_t)le32_to_cpu(hdr->len); if (dequeued_len >= 0) { size_t pkt_len; size_t bytes_to_copy; pkt_len = (size_t)le32_to_cpu(hdr->len); bytes_to_copy = min(user_buf_len, pkt_len); if (bytes_to_copy) { Loading @@ -466,7 +464,6 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, dequeued_len = err; } else { user_buf_len -= bytes_to_copy; skb_pull(skb, bytes_to_copy); } spin_lock_bh(&vvs->rx_lock); Loading @@ -484,7 +481,7 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, msg->msg_flags |= MSG_EOR; } virtio_transport_dec_rx_pkt(vvs, skb); virtio_transport_dec_rx_pkt(vvs, pkt_len); kfree_skb(skb); } Loading Loading @@ -1040,7 +1037,7 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk, spin_lock_bh(&vvs->rx_lock); can_enqueue = virtio_transport_inc_rx_pkt(vvs, skb); can_enqueue = virtio_transport_inc_rx_pkt(vvs, len); if (!can_enqueue) { free_pkt = true; goto out; Loading
tools/testing/vsock/vsock_test.c +118 −0 Original line number Diff line number Diff line Loading @@ -860,6 +860,114 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) close(fd); } #define INV_BUF_TEST_DATA_LEN 512 static void test_inv_buf_client(const struct test_opts *opts, bool stream) { unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; ssize_t ret; int fd; if (stream) fd = vsock_stream_connect(opts->peer_cid, 1234); else fd = vsock_seqpacket_connect(opts->peer_cid, 1234); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); } control_expectln("SENDDONE"); /* Use invalid buffer here. */ ret = recv(fd, NULL, sizeof(data), 0); if (ret != -1) { fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); exit(EXIT_FAILURE); } if (errno != ENOMEM) { fprintf(stderr, "unexpected recv(2) errno %d\n", errno); exit(EXIT_FAILURE); } ret = recv(fd, data, sizeof(data), MSG_DONTWAIT); if (stream) { /* For SOCK_STREAM we must continue reading. */ if (ret != sizeof(data)) { fprintf(stderr, "expected recv(2) success, got %zi\n", ret); exit(EXIT_FAILURE); } /* Don't check errno in case of success. */ } else { /* For SOCK_SEQPACKET socket's queue must be empty. */ if (ret != -1) { fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); exit(EXIT_FAILURE); } if (errno != EAGAIN) { fprintf(stderr, "unexpected recv(2) errno %d\n", errno); exit(EXIT_FAILURE); } } control_writeln("DONE"); close(fd); } static void test_inv_buf_server(const struct test_opts *opts, bool stream) { unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; ssize_t res; int fd; if (stream) fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); else fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); } res = send(fd, data, sizeof(data), 0); if (res != sizeof(data)) { fprintf(stderr, "unexpected send(2) result %zi\n", res); exit(EXIT_FAILURE); } control_writeln("SENDDONE"); control_expectln("DONE"); close(fd); } static void test_stream_inv_buf_client(const struct test_opts *opts) { test_inv_buf_client(opts, true); } static void test_stream_inv_buf_server(const struct test_opts *opts) { test_inv_buf_server(opts, true); } static void test_seqpacket_inv_buf_client(const struct test_opts *opts) { test_inv_buf_client(opts, false); } static void test_seqpacket_inv_buf_server(const struct test_opts *opts) { test_inv_buf_server(opts, false); } static struct test_case test_cases[] = { { .name = "SOCK_STREAM connection reset", Loading Loading @@ -920,6 +1028,16 @@ static struct test_case test_cases[] = { .run_client = test_seqpacket_bigmsg_client, .run_server = test_seqpacket_bigmsg_server, }, { .name = "SOCK_STREAM test invalid buffer", .run_client = test_stream_inv_buf_client, .run_server = test_stream_inv_buf_server, }, { .name = "SOCK_SEQPACKET test invalid buffer", .run_client = test_seqpacket_inv_buf_client, .run_server = test_seqpacket_inv_buf_server, }, {}, }; Loading