[PATCH 24.11 01/14] vhost/crypto: fix TOCTOU OOB write in finalize path
Maxime Coquelin
maxime.coquelin at redhat.com
Wed Oct 14 17:01:41 CEST 2026
From: Kai Ji <kai.ji at intel.com>
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")
Acked-by: Bruce Richardson <bruce.richardson at intel.com>
Signed-off-by: Kai Ji <kai.ji at intel.com>
---
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 7a5e290822..4c7ad77905 100644
--- a/lib/vhost/vhost_crypto.c
+++ b/lib/vhost/vhost_crypto.c
@@ -1298,18 +1298,23 @@ vhost_crypto_finalize_one_request(struct rte_crypto_op *op,
struct rte_mbuf *m_dst = op->sym->m_dst;
struct vhost_crypto_data_req *vc_req = rte_mbuf_to_priv(m_src);
struct vhost_virtqueue *vq;
- uint16_t used_idx, desc_idx;
+ uint16_t desc_idx;
if (unlikely(!vc_req)) {
VC_LOG_ERR("Failed to retrieve vc_req");
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 {
@@ -1317,8 +1322,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;
rte_mempool_put(m_src->pool, (void *)m_src);
@@ -1617,16 +1621,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;
}
@@ -1647,9 +1655,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
More information about the stable
mailing list