From: David Marchand <[email protected]>

Early failures (like a mempool depletion) while building a write back
chain can result in unfinished chains since the ->next field is not
explicitly set to NULL on allocation.

Such an unterminated chain results in an infinite loop and double free
issues.

CVE-2026-86847
Bugzilla ID: 2023

Fixes: cd1e8f03abf0 ("vhost/crypto: fix packet copy in chaining mode")
Cc: [email protected]

Acked-by: Bruce Richardson <[email protected]>
Signed-off-by: David Marchand <[email protected]>
---
 lib/vhost/vhost_crypto.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/lib/vhost/vhost_crypto.c b/lib/vhost/vhost_crypto.c
index a072324083..38a7bd75d6 100644
--- a/lib/vhost/vhost_crypto.c
+++ b/lib/vhost/vhost_crypto.c
@@ -859,6 +859,15 @@ copy_data(void *data, struct virtio_net *dev, struct 
vhost_virtqueue *vq,
        return 0;
 }
 
+static void
+init_wb_data(struct rte_mempool *mp __rte_unused, void *opaque __rte_unused,
+               void *obj, unsigned int obj_idx __rte_unused)
+{
+       struct vhost_crypto_writeback_data *wb_data = obj;
+
+       wb_data->next = NULL;
+}
+
 static void
 write_back_data(struct vhost_crypto_data_req *vc_req)
 {
@@ -869,6 +878,8 @@ write_back_data(struct vhost_crypto_data_req *vc_req)
                memset(wb_data->src, 0, wb_data->len);
                wb_last = wb_data;
                wb_data = wb_data->next;
+
+               wb_last->next = NULL;
                rte_mempool_put(vc_req->wb_pool, wb_last);
        }
 }
@@ -877,9 +888,10 @@ static void
 free_wb_data(struct vhost_crypto_writeback_data *wb_data,
                struct rte_mempool *mp)
 {
-       while (wb_data->next != NULL)
+       if (wb_data->next != NULL)
                free_wb_data(wb_data->next, mp);
 
+       wb_data->next = NULL;
        rte_mempool_put(mp, wb_data);
 }
 
@@ -920,7 +932,7 @@ prepare_write_back_data(struct vhost_virtqueue *vq,
                uint32_t max_n_descs)
        __rte_requires_shared_capability(&vq->iotlb_lock)
 {
-       struct vhost_crypto_writeback_data *wb_data, *head;
+       struct vhost_crypto_writeback_data *wb_data, *head = NULL;
        struct vhost_crypto_desc *desc = *cur_desc;
        uint64_t dlen;
        uint8_t *dst;
@@ -959,8 +971,7 @@ prepare_write_back_data(struct vhost_virtqueue *vq,
                        }
 
                        wb_data = wb_data->next;
-               } else
-                       wb_data->next = NULL;
+               }
        } else
                offset -= desc->len;
 
@@ -1002,8 +1013,7 @@ prepare_write_back_data(struct vhost_virtqueue *vq,
                        }
 
                        wb_data = wb_data->next;
-               } else
-                       wb_data->next = NULL;
+               }
        }
 
        if (unlikely(desc - head_desc == (int)max_n_descs))
@@ -1851,7 +1861,7 @@ rte_vhost_crypto_create(int vid, uint8_t cryptodev_id,
        vcrypto->wb_pool = rte_mempool_create(name,
                        VHOST_CRYPTO_MBUF_POOL_SIZE,
                        sizeof(struct vhost_crypto_writeback_data),
-                       128, 0, NULL, NULL, NULL, NULL,
+                       128, 0, NULL, NULL, init_wb_data, NULL,
                        rte_socket_id(), 0);
        if (!vcrypto->wb_pool) {
                VC_LOG_ERR("Failed to creath mempool");
@@ -1944,7 +1954,7 @@ rte_vhost_crypto_set_zero_copy(int vid, enum 
rte_vhost_crypto_zero_copy option)
                vcrypto->wb_pool = rte_mempool_create(name,
                                VHOST_CRYPTO_MBUF_POOL_SIZE,
                                sizeof(struct vhost_crypto_writeback_data),
-                               128, 0, NULL, NULL, NULL, NULL,
+                               128, 0, NULL, NULL, init_wb_data, NULL,
                                rte_socket_id(), 0);
                if (!vcrypto->wb_pool) {
                        VC_LOG_ERR("Failed to creath mbuf pool");
-- 
2.56.0

Reply via email to