From 3b431afba4814ff44cfb9e3afc3ce075c653558c Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 4 May 2026 21:52:42 +0200 Subject: [PATCH] virtio-devices: Check MSI-X vector bounds before table access A malicious or buggy guest can write an out-of-bounds value to queue_msix_vector or msix_config. When the device later triggers an interrupt, it indexes into table_entries with the unchecked vector, causing a panic. Validate the vector against the MSI-X table size in both trigger() and notifier() paths, logging a warning and returning early when the vector exceeds the table bounds. Signed-off-by: Anatol Belski --- virtio-devices/src/transport/pci_device.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs index 619336e89..dc71be40d 100644 --- a/virtio-devices/src/transport/pci_device.rs +++ b/virtio-devices/src/transport/pci_device.rs @@ -15,7 +15,7 @@ use std::sync::{Arc, Barrier, Mutex}; use anyhow::anyhow; use libc::EFD_NONBLOCK; -use log::{error, info}; +use log::{error, info, warn}; use pci::{ BarReprogrammingParams, MaybeMutInterruptSourceGroup, MsixCap, MsixConfig, PciBarConfiguration, PciBarRegionType, PciCapability, PciCapabilityId, PciClassCode, PciConfiguration, PciDevice, @@ -860,6 +860,7 @@ pub struct VirtioInterruptMsix { config_vector: Arc, queues_vectors: Arc>>, interrupt_source_group: MaybeMutInterruptSourceGroup, + msix_table_size: usize, } impl VirtioInterruptMsix { @@ -869,11 +870,13 @@ impl VirtioInterruptMsix { queues_vectors: Arc>>, interrupt_source_group: MaybeMutInterruptSourceGroup, ) -> Self { + let msix_table_size = msix_config.lock().unwrap().table_entries.len(); VirtioInterruptMsix { msix_config, config_vector, queues_vectors, interrupt_source_group, + msix_table_size, } } } @@ -891,6 +894,11 @@ impl VirtioInterrupt for VirtioInterruptMsix { return Ok(()); } + if vector as usize >= self.msix_table_size { + warn!("MSI-X vector {vector} out of range, ignoring interrupt"); + return Ok(()); + } + let config = &mut self.msix_config.lock().unwrap(); let entry = &config.table_entries[vector as usize]; // In case the vector control register associated with the entry @@ -915,6 +923,15 @@ impl VirtioInterrupt for VirtioInterruptMsix { } }; + if vector == VIRTQ_MSI_NO_VECTOR { + return None; + } + + if vector as usize >= self.msix_table_size { + warn!("MSI-X vector {vector} out of range, notifier unavailable"); + return None; + } + self.interrupt_source_group .notifier(vector as InterruptIndex) }