From: Wen Qian <qian.wen@...>
The current code would cause infinite calls to vq_getchain()
because that:
- error check of vq_getchain() return value is missing.
- virtqueue misunderstand that there are avaliable descripters
even though the idx of avail ring is invalid.
This patch fixes it by checking validity of the return of
vq_getchain() and jump out of the loop for invalid return value.
This patch alse add validity check in judgment of avaliable
descriptor, and check if the diff between idx of avail ring and
the last idx is greater than size of this queue.
Signed-off-by: Wen Qian <qian.wen@...>
Signed-off-by: Li Fei <fei1.li@...>
---
devicemodel/hw/pci/virtio/virtio_console.c | 9 ++++++++-
devicemodel/hw/pci/virtio/virtio_gpio.c | 2 +-
devicemodel/hw/pci/virtio/virtio_rnd.c | 5 ++++-
devicemodel/include/virtio.h | 4 ++++
4 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/devicemodel/hw/pci/virtio/virtio_console.c b/devicemodel/hw/pci/virtio/virtio_console.c
index 75f50614e..d3b0fb857 100644
--- a/devicemodel/hw/pci/virtio/virtio_console.c
+++ b/devicemodel/hw/pci/virtio/virtio_console.c
@@ -392,7 +392,10 @@ virtio_console_notify_tx(void *vdev, struct virtio_vq_info *vq)
port = virtio_console_vq_to_port(console, vq);
while (vq_has_descs(vq)) {
- vq_getchain(vq, &idx, iov, 1, flags);
+ if (vq_getchain(vq, &idx, iov, 1, flags) < 1) {
+ pr_err("%s: fail to getchain!\n", __func__);
+ break;
+ }
if ((port != NULL) && (port->cb != NULL))
port->cb(port, port->arg, iov, 1);
@@ -481,6 +484,10 @@ virtio_console_backend_read(int fd __attribute__((unused)),
do {
n = vq_getchain(vq, &idx, &iov, 1, NULL);
+ if (n < 1){
+ pr_err("%s: fail to getchain!\n", __func__);
+ break;
+ }
len = readv(be->fd, &iov, n);
if (len <= 0) {
vq_retchain(vq);
diff --git a/devicemodel/hw/pci/virtio/virtio_gpio.c b/devicemodel/hw/pci/virtio/virtio_gpio.c
index ed70e2444..110f6bacd 100644
--- a/devicemodel/hw/pci/virtio/virtio_gpio.c
+++ b/devicemodel/hw/pci/virtio/virtio_gpio.c
@@ -688,7 +688,7 @@ virtio_gpio_notify(void *vdev, struct virtio_vq_info *vq)
gpio = (struct virtio_gpio *)vdev;
if (vq_has_descs(vq)) {
n = vq_getchain(vq, &idx, iov, 2, NULL);
- if (n >= 3) {
+ if (n < 1 || n >= 3) {
WPRINTF(("virtio gpio, invalid chain number %d\n", n));
virtio_gpio_abort(vq, idx);
return;
diff --git a/devicemodel/hw/pci/virtio/virtio_rnd.c b/devicemodel/hw/pci/virtio/virtio_rnd.c
index 247142320..2beec5016 100644
--- a/devicemodel/hw/pci/virtio/virtio_rnd.c
+++ b/devicemodel/hw/pci/virtio/virtio_rnd.c
@@ -322,7 +322,10 @@ virtio_rnd_get_entropy(void *param)
pthread_mutex_unlock(&rnd->rx_mtx);
do {
- vq_getchain(vq, &idx, &iov, 1, NULL);
+ if (vq_getchain(vq, &idx, &iov, 1, NULL) < 1) {
+ pr_err("%s: fail to getchain!\n", __func__);
+ break;
+ }
len = read(rnd->fd, iov.iov_base, iov.iov_len);
if (len <= 0) {
vq_retchain(vq);
diff --git a/devicemodel/include/virtio.h b/devicemodel/include/virtio.h
index 5793db382..c2c7ae1b0 100644
--- a/devicemodel/include/virtio.h
+++ b/devicemodel/include/virtio.h
@@ -477,6 +477,10 @@ vq_ring_ready(struct virtio_vq_info *vq)
static inline bool
vq_has_descs(struct virtio_vq_info *vq)
{
+ if ((uint16_t)((u_int)vq->avail->idx - vq->last_avail) > vq->qsize) {
+ pr_err ("%s: no valid descriptor\n", vq->base->vops->name);
+ return false;
+ }
return (vq_ring_ready(vq) && vq->last_avail !=
vq->avail->idx);
}
--
2.17.1