summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Garzarella <sgarzare@redhat.com>2020-10-08 22:42:56 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-11-05 11:08:53 +0100
commit5b14ac3b9404f18591deb81913ab708642b2a4bd (patch)
tree351b69178c04b4b08051a49fa43c4a2811a2bab5
parent57ebe9102928e835d72ffec43c7995723cfea132 (diff)
downloadlinux-stable-5b14ac3b9404f18591deb81913ab708642b2a4bd.tar.gz
linux-stable-5b14ac3b9404f18591deb81913ab708642b2a4bd.tar.bz2
linux-stable-5b14ac3b9404f18591deb81913ab708642b2a4bd.zip
vringh: fix __vringh_iov() when riov and wiov are different
commit 5745bcfbbf89b158416075374254d3c013488f21 upstream. If riov and wiov are both defined and they point to different objects, only riov is initialized. If the wiov is not initialized by the caller, the function fails returning -EINVAL and printing "Readable desc 0x... after writable" error message. This issue happens when descriptors have both readable and writable buffers (eg. virtio-blk devices has virtio_blk_outhdr in the readable buffer and status as last byte of writable buffer) and we call __vringh_iov() to get both type of buffers in two different iovecs. Let's replace the 'else if' clause with 'if' to initialize both riov and wiov if they are not NULL. As checkpatch pointed out, we also avoid crashing the kernel when riov and wiov are both NULL, replacing BUG() with WARN_ON() and returning -EINVAL. Fixes: f87d0fbb5798 ("vringh: host-side implementation of virtio rings.") Cc: stable@vger.kernel.org Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Link: https://lore.kernel.org/r/20201008204256.162292-1-sgarzare@redhat.com Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/vhost/vringh.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
index a94d700a4503..59c61744dcc1 100644
--- a/drivers/vhost/vringh.c
+++ b/drivers/vhost/vringh.c
@@ -273,13 +273,14 @@ __vringh_iov(struct vringh *vrh, u16 i,
desc_max = vrh->vring.num;
up_next = -1;
+ /* You must want something! */
+ if (WARN_ON(!riov && !wiov))
+ return -EINVAL;
+
if (riov)
riov->i = riov->used = 0;
- else if (wiov)
+ if (wiov)
wiov->i = wiov->used = 0;
- else
- /* You must want something! */
- BUG();
for (;;) {
void *addr;