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 <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-05-04 21:52:42 +02:00
committed by Rob Bradford
parent 376434a695
commit 3b431afba4

View File

@@ -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<AtomicU16>,
queues_vectors: Arc<Mutex<Vec<u16>>>,
interrupt_source_group: MaybeMutInterruptSourceGroup,
msix_table_size: usize,
}
impl VirtioInterruptMsix {
@@ -869,11 +870,13 @@ impl VirtioInterruptMsix {
queues_vectors: Arc<Mutex<Vec<u16>>>,
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)
}