| From 5745bcfbbf89b158416075374254d3c013488f21 Mon Sep 17 00:00:00 2001 |
| From: Stefano Garzarella <sgarzare@redhat.com> |
| Date: Thu, 8 Oct 2020 22:42:56 +0200 |
| Subject: vringh: fix __vringh_iov() when riov and wiov are different |
| |
| From: Stefano Garzarella <sgarzare@redhat.com> |
| |
| 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> |
| |
| --- |
| drivers/vhost/vringh.c | 9 +++++---- |
| 1 file changed, 5 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/vhost/vringh.c |
| +++ b/drivers/vhost/vringh.c |
| @@ -284,13 +284,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; |