Skip to contentSkip to conversation

vhost-crypto TOCTOU out-of-bounds write

DPDK/vhost/virtio Bug 2001 [email protected] 1 participant 1 message Aug 28

lore
Share & tools
lore
#0 lore raw

https://bugs.dpdk.org/show_bug.cgi?id=2001

Bug ID: 2001
Summary: vhost-crypto TOCTOU out-of-bounds write
Product: DPDK
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Severity: normal
Priority: Normal
Component: vhost/virtio
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
Group: security

Report date: 2026-03-11
Reported by: Adiel Sol <[email protected]>

Hi DPDK Security Team,
I would like to report a security vulnerability in DPDK vhost-crypto. Summary
The vhost-crypto code has a time-of-check to time-of-use (TOCTOU) bug in the path that finalizes a crypto request. When the host finishes a request, it writes the result into the virtio used ring. The descriptor index for that write is read again from the guest-writable available ring at finalization time, and the code does not check that this index is within the virtqueue size. Between the initial fetch and finalization, a malicious guest can change that value in shared memory. The host then uses the guest-controlled value as an index and writes to vq->used->ring[desc_idx], causing an out-of-bounds write (up to about 524 KB past the used ring when the index is 0xFFFF). The used ring has only 256 entries. A malicious guest with a vhost-crypto device can trigger this to corrupt host DPDK process memory. In practice this can lead to host crash or arbitrary code execution on the host (guest escape). Because the DPDK process usually runs as root, a successful exploit can mean full control of the host.
Affected Component

* lib/vhost/vhost_crypto.c (finalize path; function
vhost_crypto_finalize_one_request() and the code that re-reads desc_idx from vq->avail->ring[used_idx] and writes to vq->used->ring[desc_idx] without validation).
* Versions: DPDK 26.03.0-rc1 and earlier versions that include the
vhost-crypto finalize path. Any product that uses DPDK vhost-crypto in the same way may be affected.

Root Cause
At fetch time the host correctly masks used_idx and reads desc_idx from the available ring. At finalize time the code reads desc_idx again from vq->avail->ring[used_idx] (guest-writable shared memory) and then writes vq->used->ring[desc_idx].id and .len with no check that desc_idx < vq->size. The available ring is writable by the guest at any time. Between fetch and finalize the host is busy with the crypto operation (enqueue to cryptodev, wait for completion), so the guest has a long race window (microseconds to milliseconds) to overwrite vq->avail->ring[used_idx] with any 16-bit value (e.g. 0xFFFF). The host then uses that value as an index. The used ring has only vq->size entries (e.g. 256), so indexing with 0xFFFF causes a write at 65535 * 8 bytes past the start of the ring, i.e. an out-of-bounds write into host process memory. The attacker controls the write offset and partially the written data (the .id value comes from another guest-controlled slot; the .len from the request). So the bug is a TOCTOU with missing input validation (CWE-367, CWE-787, CWE-20).
Impact

* CVSS 3.1: High (e.g. AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H or similar;
guest-to-host escape, host RCE in scope).
* CWE-787 (Out-of-bounds Write), CWE-367 (TOCTOU Race Condition), CWE-20
(Improper Input Validation).
* A malicious guest VM with a vhost-crypto device can trigger the overflow
by submitting a valid crypto request and then overwriting the available ring slot during the crypto operation. No special guest setup is required; the race window is the duration of the crypto operation.
* Successful exploitation can lead to memory corruption in the host DPDK
process, then to arbitrary code execution on the host (guest escape) and full compromise of the host (backdoors, pivot, etc.), often as root.

Proof of Concept

1. We provide two proof-of-concept programs that simulate the vulnerable
pattern (shared virtqueue, host thread, guest thread). They do not run against a full DPDK build but demonstrate the TOCTOU and the resulting out-of-bounds access and control-flow hijack.
2.
OOB detection: In the PoC directory, run ./run_poc.sh. The code is built with AddressSanitizer. The host thread fetches a request (reads desc_idx = 0), then the guest thread overwrites the available ring slot to 0xFFFF. When the host thread finalizes, it re-reads desc_idx and writes to used_ring[0xFFFF]. AddressSanitizer reports a SEGV (or heap-buffer-overflow) in the host thread at the finalize line, proving the out-of-bounds access.
3.
Control-flow hijack (guest escape / RCE): Run make run-rce in the same directory. The layout is set so that used_ring[256] (one past the end) overwrites a function pointer. The guest sets desc_idx = 256 and the two 32-bit halves of the payload address. When the host calls the completion callback after finalize, it runs the attacker-supplied function. The program prints "PWNED: guest escape - host is now running attacker code!" This shows that the same primitive can redirect execution and is sufficient to demonstrate the guest-escape / RCE impact in concept.
4.
The PoC sources, build instructions, and a captured ASan run are in the disclosure package (e.g. poc-dpdk-vhost-crypto-toctou/ with vhost_crypto_toctou_poc.c, vhost_toctou_rce_poc.c, run_poc.sh, PROOF-OUTPUT.txt).

Credit Request
We kindly request that the following researchers be credited for this discovery:
Adiel Sol, Arad Inbar, Erez Cohen, Nir Somech, Ben Grinberg, Daniel Lubel – DREAM Security Research Team

Signature · 2 lines
You are receiving this mail because:
You are the assignee for the bug.