diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 0cb87971d749..88a310390eb0 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -360,7 +360,7 @@ static struct sk_buff * vhost_vsock_alloc_skb(struct vhost_virtqueue *vq, unsigned int out, unsigned int in) { - struct virtio_vsock_hdr *hdr; + struct virtio_vsock_hdr hdr; struct iov_iter iov_iter; struct sk_buff *skb; size_t payload_len; @@ -378,34 +378,32 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq, len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM) return NULL; - /* len contains both payload and hdr */ - skb = virtio_vsock_alloc_skb(len, GFP_KERNEL); - if (!skb) - return NULL; - iov_iter_init(&iov_iter, ITER_SOURCE, vq->iov, out, len); - hdr = virtio_vsock_hdr(skb); - nbytes = copy_from_iter(hdr, sizeof(*hdr), &iov_iter); - if (nbytes != sizeof(*hdr)) { + nbytes = copy_from_iter(&hdr, sizeof(hdr), &iov_iter); + if (nbytes != sizeof(hdr)) { vq_err(vq, "Expected %zu bytes for pkt->hdr, got %zu bytes\n", - sizeof(*hdr), nbytes); - kfree_skb(skb); + sizeof(hdr), nbytes); return NULL; } - payload_len = le32_to_cpu(hdr->len); + payload_len = le32_to_cpu(hdr.len); + + /* The pkt is too big or the length in the header is invalid */ + if (payload_len > len - sizeof(hdr)) + return NULL; + + /* Allocate only for the payload declared in the header. */ + skb = virtio_vsock_alloc_skb(payload_len + sizeof(hdr), GFP_KERNEL); + if (!skb) + return NULL; + + memcpy(virtio_vsock_hdr(skb), &hdr, sizeof(hdr)); /* No payload */ if (!payload_len) return skb; - /* The pkt is too big or the length in the header is invalid */ - if (payload_len + sizeof(*hdr) > len) { - kfree_skb(skb); - return NULL; - } - virtio_vsock_skb_put(skb, payload_len); if (skb_copy_datagram_from_iter(skb, 0, &iov_iter, payload_len)) {