From: Kai Ji <[email protected]>
When finalizing a crypto request, the descriptor index was
re-read from the guest-writable available ring (vq->avail->ring)
instead of using the value saved at request fetch time. A malicious
guest can modify this index between fetch and finalization, causing
an out-of-bounds write to vq->used->ring[desc_idx] with a
guest-controlled index up to 0xFFFF (max ~512 KB past the ring).
Fix by using the desc_idx saved in vc_req->desc_idx directly at
finalization time, eliminating the re-read from guest memory. Add
bounds checks on desc_idx against vq->size in both the fetch loops
and the finalize function to prevent out-of-bounds access.
CVE-2026-86848
CVE-2026-86846
Bugzilla ID: 2001
Bugzilla ID: 2026
Fixes: 939066d96563 ("vhost/crypto: add public function implementation")
Cc: [email protected]
Acked-by: Bruce Richardson <[email protected]>
Signed-off-by: Kai Ji <[email protected]>
---
lib/vhost/vhost_crypto.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/lib/vhost/vhost_crypto.c b/lib/vhost/vhost_crypto.c
index 648e2d731b..351fa241c8 100644
--- a/lib/vhost/vhost_crypto.c
+++ b/lib/vhost/vhost_crypto.c
@@ -1707,7 +1707,7 @@ vhost_crypto_finalize_one_request(struct rte_crypto_op
*op,
struct rte_mbuf *m_src = NULL, *m_dst = NULL;
struct vhost_crypto_data_req *vc_req;
struct vhost_virtqueue *vq;
- uint16_t used_idx, desc_idx;
+ uint16_t desc_idx;
if (op->type == RTE_CRYPTO_OP_TYPE_SYMMETRIC) {
m_src = op->sym->m_src;
@@ -1725,11 +1725,16 @@ vhost_crypto_finalize_one_request(struct rte_crypto_op
*op,
return NULL;
}
vq = vc_req->vq;
- used_idx = vc_req->desc_idx;
+ desc_idx = vc_req->desc_idx;
if (old_vq && (vq != old_vq))
return vq;
+ if (unlikely(desc_idx >= vq->size)) {
+ VC_LOG_ERR("Invalid descriptor index %u", desc_idx);
+ return NULL;
+ }
+
if (unlikely(op->status != RTE_CRYPTO_OP_STATUS_SUCCESS))
vc_req->inhdr->status = VIRTIO_CRYPTO_ERR;
else {
@@ -1737,8 +1742,7 @@ vhost_crypto_finalize_one_request(struct rte_crypto_op
*op,
write_back_data(vc_req);
}
- desc_idx = vq->avail->ring[used_idx];
- vq->used->ring[desc_idx].id = vq->avail->ring[desc_idx];
+ vq->used->ring[desc_idx].id = desc_idx;
vq->used->ring[desc_idx].len = vc_req->len;
if (op->type == RTE_CRYPTO_OP_TYPE_SYMMETRIC) {
@@ -2044,16 +2048,20 @@ rte_vhost_crypto_fetch_requests(int vid, uint32_t qid,
for (i = 0; i < count; i++) {
uint16_t used_idx = (start_idx + i) & (vq->size - 1);
uint16_t desc_idx = vq->avail->ring[used_idx];
- struct vring_desc *head = &vq->desc[desc_idx];
+ struct vring_desc *head;
struct rte_crypto_op *op = ops[i];
+ if (unlikely(desc_idx >= vq->size))
+ break;
+
+ head = &vq->desc[desc_idx];
op->sym->m_src = mbufs[i * 2];
op->sym->m_dst = mbufs[i * 2 + 1];
op->sym->m_src->data_off = 0;
op->sym->m_dst->data_off = 0;
if (unlikely(vhost_crypto_process_one_req(vcrypto, vq,
- op, head, descs, used_idx) < 0))
+ op, head, descs, desc_idx) < 0))
break;
}
@@ -2074,9 +2082,13 @@ rte_vhost_crypto_fetch_requests(int vid, uint32_t qid,
for (i = 0; i < count; i++) {
uint16_t used_idx = (start_idx + i) & (vq->size - 1);
uint16_t desc_idx = vq->avail->ring[used_idx];
- struct vring_desc *head = &vq->desc[desc_idx];
+ struct vring_desc *head;
struct rte_crypto_op *op = ops[i];
+ if (unlikely(desc_idx >= vq->size))
+ break;
+
+ head = &vq->desc[desc_idx];
op->sym->m_src = mbufs[i];
op->sym->m_dst = NULL;
op->sym->m_src->data_off = 0;
--
2.56.0