-
Notifications
You must be signed in to change notification settings - Fork 0
refine: Refine virtio-pci #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| use std::sync::Arc; | ||
| use std::sync::Mutex; | ||
|
|
||
| use vm_mm::allocator::MemoryContainer; | ||
| use vm_pci::device::function::BarHandler; | ||
|
|
||
| use crate::device::pci::VirtioPciDevice; | ||
| use crate::transport::VirtioDev; | ||
|
|
||
| pub struct DeviceHandler<C, D> | ||
| where | ||
| C: MemoryContainer, | ||
| D: VirtioPciDevice<C>, | ||
| { | ||
| pub dev: Arc<Mutex<VirtioDev<C, D>>>, | ||
| } | ||
|
|
||
| impl<C, D> BarHandler for DeviceHandler<C, D> | ||
| where | ||
| C: MemoryContainer, | ||
| D: VirtioPciDevice<C>, | ||
| { | ||
| fn read(&self, offset: u64, data: &mut [u8]) { | ||
| let dev = self.dev.lock().unwrap(); | ||
|
|
||
| dev.read_config(offset.try_into().unwrap(), data.len(), data) | ||
| .unwrap(); | ||
|
Comment on lines
+23
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n crates/vm-virtio/src/transport/pci/device_handler.rs | head -50Repository: junyu0312/rust-vm Length of output: 1147 🏁 Script executed: rg -n 'fn read_config|fn write_config' crates/vm-virtio/src/ -A 3Repository: junyu0312/rust-vm Length of output: 973 🏁 Script executed: rg -n 'pub fn read_config|pub fn write_config' crates/vm-virtio/src/ -A 3Repository: junyu0312/rust-vm Length of output: 658 🏁 Script executed: rg -n 'BarHandler' crates/vm-virtio/src/ -B 2 -A 2Repository: junyu0312/rust-vm Length of output: 3925 🏁 Script executed: rg -n 'impl.*BarHandler' crates/vm-virtio/src/ -B 2 -A 10Repository: junyu0312/rust-vm Length of output: 4224 🏁 Script executed: rg -n 'Result<' crates/vm-virtio/src/device.rs -B 1 -A 1 | head -40Repository: junyu0312/rust-vm Length of output: 253 🏁 Script executed: # Check if there are other BarHandler implementations with different error handling
fd -e rs -x rg -l 'impl.*BarHandler' {} \;Repository: junyu0312/rust-vm Length of output: 284 🏁 Script executed: cat -n crates/vm-virtio/src/transport/pci/common_config_handler.rs | head -80Repository: junyu0312/rust-vm Length of output: 2945 🏁 Script executed: rg -n 'fn read|fn write' crates/vm-virtio/src/transport/pci/common_config_handler.rs -A 15Repository: junyu0312/rust-vm Length of output: 1405 🏁 Script executed: rg -n 'lock().unwrap()' crates/vm-virtio/src/transport/pci/ -B 2 -A 2Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Check if there's any documented policy on error handling for guest-triggered operations
rg -n 'guest|BAR|handler' crates/vm-virtio/src/ -i --max-count=5 | head -20Repository: junyu0312/rust-vm Length of output: 1961 Handle invalid PCI config offsets and operation failures gracefully instead of panicking. Lines 26-27 and 33-34 unwrap on guest-supplied offset conversion and fallible config operations. These unwraps can be triggered by malicious or misconfigured guests and will crash the service. The codebase already establishes the correct pattern in Errors from 🛠️ Defensive handling proposal+use tracing::warn;
+
impl<C, D> BarHandler for DeviceHandler<C, D>
where
C: MemoryContainer,
D: VirtioPciDevice<C>,
{
fn read(&self, offset: u64, data: &mut [u8]) {
+ let Ok(offset) = usize::try_from(offset) else {
+ warn!(offset, "PCI config read offset too large");
+ data.fill(0);
+ return;
+ };
let dev = self.dev.lock().unwrap();
-
- dev.read_config(offset.try_into().unwrap(), data.len(), data)
- .unwrap();
+ if let Err(err) = dev.read_config(offset, data.len(), data) {
+ warn!(?err, offset, len = data.len(), "PCI config read failed");
+ data.fill(0);
+ }
}
fn write(&self, offset: u64, data: &[u8]) {
+ let Ok(offset) = usize::try_from(offset) else {
+ warn!(offset, "PCI config write offset too large");
+ return;
+ };
let mut dev = self.dev.lock().unwrap();
-
- dev.write_config(offset.try_into().unwrap(), data.len(), data)
- .unwrap();
+ if let Err(err) = dev.write_config(offset, data.len(), data) {
+ warn!(?err, offset, len = data.len(), "PCI config write failed");
+ }
}
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| fn write(&self, offset: u64, data: &[u8]) { | ||
| let mut dev = self.dev.lock().unwrap(); | ||
|
|
||
| dev.write_config(offset.try_into().unwrap(), data.len(), data) | ||
| .unwrap(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,41 @@ | ||||||||||||||
| use std::sync::Arc; | ||||||||||||||
| use std::sync::Mutex; | ||||||||||||||
|
|
||||||||||||||
| use vm_mm::allocator::MemoryContainer; | ||||||||||||||
| use vm_pci::device::function::BarHandler; | ||||||||||||||
|
|
||||||||||||||
| use crate::device::pci::VirtioPciDevice; | ||||||||||||||
| use crate::transport::VirtioDev; | ||||||||||||||
| use crate::transport::control_register::ControlRegister; | ||||||||||||||
|
|
||||||||||||||
| pub struct IsrHandler<C, D> | ||||||||||||||
| where | ||||||||||||||
| C: MemoryContainer, | ||||||||||||||
| D: VirtioPciDevice<C>, | ||||||||||||||
| { | ||||||||||||||
| pub dev: Arc<Mutex<VirtioDev<C, D>>>, | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| impl<C, D> BarHandler for IsrHandler<C, D> | ||||||||||||||
| where | ||||||||||||||
| C: MemoryContainer, | ||||||||||||||
| D: VirtioPciDevice<C>, | ||||||||||||||
| { | ||||||||||||||
| fn read(&self, _offset: u64, data: &mut [u8]) { | ||||||||||||||
| let mut dev = self.dev.lock().unwrap(); | ||||||||||||||
|
|
||||||||||||||
| let isr = dev.read_reg(ControlRegister::InterruptStatus); | ||||||||||||||
| data[0] = isr as u8; | ||||||||||||||
|
|
||||||||||||||
| /* | ||||||||||||||
| * From `4.1.4.5.1 Device Requirements: ISR status capability` | ||||||||||||||
| * - The device MUST reset ISR status to 0 on driver read. | ||||||||||||||
| */ | ||||||||||||||
| dev.write_reg(ControlRegister::InterruptStatus, 0).unwrap(); | ||||||||||||||
| dev.device.trigger_irq(false); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+24
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's see the actual file content and surrounding code
cat -n crates/vm-virtio/src/transport/pci/isr_handler.rs | head -50Repository: junyu0312/rust-vm Length of output: 1392 🏁 Script executed: # Let's also find the BarHandler trait definition
rg -A 10 "trait BarHandler" --type rustRepository: junyu0312/rust-vm Length of output: 724 🏁 Script executed: # Check for any documentation or spec references in the codebase
rg "InterruptStatus" -B 3 -A 3 --type rust | head -40Repository: junyu0312/rust-vm Length of output: 3338 🏁 Script executed: # Let's check if there's spec documentation or comments about the ISR capability
rg "4.1.4.5.1" -B 5 -A 5 --type rustRepository: junyu0312/rust-vm Length of output: 982 🏁 Script executed: # Check how BarHandler is used when calling these functions
rg "\.read\(" crates/vm-pci -B 3 -A 3 --type rust | head -60Repository: junyu0312/rust-vm Length of output: 1649 🏁 Script executed: # Check the VirtioDev definition to understand the register size
rg "struct VirtioDev" -A 20 --type rust | head -40Repository: junyu0312/rust-vm Length of output: 1239 🏁 Script executed: # Look for any test cases or usage of ISR reads
rg "InterruptStatus" crates/vm-virtio -B 2 -A 2 --type rust | grep -A 2 -B 2 "read\|offset"Repository: junyu0312/rust-vm Length of output: 1548 🏁 Script executed: # Check how the MMIO handler processes ISR reads to compare behavior
rg -A 10 "InterruptAck|InterruptStatus" crates/vm-virtio/src/transport/mmio/mmio_handler.rs | head -60Repository: junyu0312/rust-vm Length of output: 1555 🏁 Script executed: # Check if there are actual test cases or callers of the ISR handler
rg "IsrHandler" -B 2 -A 5 --type rustRepository: junyu0312/rust-vm Length of output: 2499 🏁 Script executed: # Look at how BAR reads are invoked at the PCI level
rg "bar_handler.read" -B 5 -A 5 --type rustRepository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Check if there's any validation of buffer size in other BarHandler implementations
fd "handler\.rs|bar.*\.rs" --type f | xargs grep -l "BarHandler" | head -5Repository: junyu0312/rust-vm Length of output: 276 🏁 Script executed: # Check other BarHandler implementations for how they handle buffers
cat -n crates/vm-virtio/src/transport/pci/common_config_handler.rs | head -100Repository: junyu0312/rust-vm Length of output: 4009 🏁 Script executed: # Check the device_handler implementation
cat -n crates/vm-virtio/src/transport/pci/device_handler.rs | head -100Repository: junyu0312/rust-vm Length of output: 1147 🏁 Script executed: # Check notify_handler implementation
cat -n crates/vm-virtio/src/transport/pci/notify_handler.rs | head -100Repository: junyu0312/rust-vm Length of output: 1192 🏁 Script executed: # Look at the PCI BAR routing to understand if empty buffers are possible
rg "bar_handler.read\|bar_handler.write" -B 10 -A 3 --type rustRepository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Check the VirtIO PCI spec reference - look for ISR capability definition
rg "4.1.4" -B 2 -A 10 --type rustRepository: junyu0312/rust-vm Length of output: 1068 🏁 Script executed: # Check if there are any tests for the ISR handler
find . -name "*.rs" -type f | xargs grep -l "IsrHandler" | xargs grep -l "test\|#\[cfg(test)]"Repository: junyu0312/rust-vm Length of output: 45 🏁 Script executed: # Look for how BAR reads are actually called - check the PCI root complex
cat -n crates/vm-pci/src/root_complex/mmio/bar_handler.rsRepository: junyu0312/rust-vm Length of output: 2158 🏁 Script executed: # Verify the ISR register size from VirtIO spec - check device implementation
rg "read_reg.*InterruptStatus\|InterruptStatus.*u8\|InterruptStatus.*u32" -B 2 -A 2 --type rust | head -40Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Check if there's a specific BAR size for ISR capability
rg "Bar.*Bar2\|IsrHandler" -B 5 -A 5 --type rust | grep -A 5 -B 5 "Bar2"Repository: junyu0312/rust-vm Length of output: 43 Guard ISR read size and offset before acknowledging interrupts. Line 28 accesses Validate that 🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| fn write(&self, _offset: u64, _data: &[u8]) { | ||||||||||||||
| unreachable!() | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+38
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n crates/vm-virtio/src/transport/pci/isr_handler.rsRepository: junyu0312/rust-vm Length of output: 1392 🏁 Script executed: rg -n "BarHandler" crates/vm-virtio/src/transport/pci/ -A 10 -B 2Repository: junyu0312/rust-vm Length of output: 8426 🏁 Script executed: sed -n '85,150p' crates/vm-virtio/src/transport/pci/common_config_handler.rsRepository: junyu0312/rust-vm Length of output: 2935 🏁 Script executed: cat -n crates/vm-virtio/src/transport/pci/notify_handler.rsRepository: junyu0312/rust-vm Length of output: 1192 🏁 Script executed: rg -n "BarHandler" --type rust -B 3 -A 3 | head -60Repository: junyu0312/rust-vm Length of output: 3671 🏁 Script executed: cat -n crates/vm-pci/src/root_complex/mmio_router.rs | head -100Repository: junyu0312/rust-vm Length of output: 2240 🏁 Script executed: rg -n "\.read\(|\.write\(" crates/vm-pci/src/root_complex/ -B 5 -A 5Repository: junyu0312/rust-vm Length of output: 2998 Replace unreachable!() with a graceful ignore for guest ISR writes. The ISR status capability is read-only per Virtio specification, but a guest can still attempt writes to the ISR BAR offset through a MMIO write. The current Suggested fix fn write(&self, _offset: u64, _data: &[u8]) {
- unreachable!()
+ // ISR status is read-only; guest writes are ignored.
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| use std::sync::Arc; | ||
| use std::sync::Mutex; | ||
|
|
||
| use vm_mm::allocator::MemoryContainer; | ||
| use vm_pci::device::function::BarHandler; | ||
|
|
||
| use crate::device::pci::VirtioPciDevice; | ||
| use crate::transport::VirtioDev; | ||
| use crate::transport::control_register::ControlRegister; | ||
|
|
||
| pub struct NotifyHandler<C, D> | ||
| where | ||
| C: MemoryContainer, | ||
| D: VirtioPciDevice<C>, | ||
| { | ||
| pub dev: Arc<Mutex<VirtioDev<C, D>>>, | ||
| } | ||
|
|
||
| impl<C, D> BarHandler for NotifyHandler<C, D> | ||
| where | ||
| C: MemoryContainer, | ||
| D: VirtioPciDevice<C>, | ||
| { | ||
| fn read(&self, _offset: u64, _data: &mut [u8]) { | ||
| unreachable!() | ||
| } | ||
|
|
||
| fn write(&self, _offset: u64, data: &[u8]) { | ||
| assert_eq!(data.len(), 2); | ||
| let queue_index = u16::from_le_bytes(data.try_into().unwrap()); | ||
| let mut dev = self.dev.lock().unwrap(); | ||
| dev.write_reg(ControlRegister::QueueNotify, queue_index.into()) | ||
| .unwrap(); | ||
|
Comment on lines
+24
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n crates/vm-virtio/src/transport/pci/notify_handler.rsRepository: junyu0312/rust-vm Length of output: 1192 🏁 Script executed: # Find BarHandler trait definition
rg -n 'trait BarHandler' --type rustRepository: junyu0312/rust-vm Length of output: 135 🏁 Script executed: # Find where NotifyHandler is used as BarHandler
rg -n 'NotifyHandler.*BarHandler\|impl.*BarHandler.*NotifyHandler' crates/vm-virtio/src --type rust -A5Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Check how BAR operations are dispatched to handlers
rg -n '\.read\(.*offset\|\.write\(.*offset' crates/vm-virtio/src/transport/pci --type rust -B2 -A2Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Understand the call chain from guest BAR access
rg -n 'BarHandler\|NotifyHandler' crates/vm-virtio/src/transport/pci --type rust | head -20Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: cat -n crates/vm-pci/src/device/function.rs | head -50Repository: junyu0312/rust-vm Length of output: 735 🏁 Script executed: # Search for how BAR reads/writes are dispatched
rg -n 'BarHandler' crates/vm-pci/src --type rust -B3 -A3Repository: junyu0312/rust-vm Length of output: 5116 🏁 Script executed: # Find where handlers are called
rg -n 'handler\.read\|handler\.write' crates --type rust -B2 -A2Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Look for NotifyHandler instantiation
rg -n 'NotifyHandler' crates --type rustRepository: junyu0312/rust-vm Length of output: 445 🏁 Script executed: # Find where handler.read and handler.write are called from MMIO access
rg -n 'handler\.read|handler\.write' crates/vm-pci --type rust -B5 -A3Repository: junyu0312/rust-vm Length of output: 1735 🏁 Script executed: # Look for MMIO access dispatch in the router
cat -n crates/vm-pci/src/root_complex/mmio_router.rsRepository: junyu0312/rust-vm Length of output: 2240 🏁 Script executed: # Verify the dispatcher is called from guest MMIO access path
rg -n 'pub fn read|pub fn write' crates/vm-pci/src/root_complex/mmio/bar_handler.rs -B2 -A10Repository: junyu0312/rust-vm Length of output: 43 🏁 Script executed: # Check what triggers the MMIO dispatcher
rg -n 'BarHandler|bar_handler' crates/vm-core/src --type rust 2>/dev/null | head -20Repository: junyu0312/rust-vm Length of output: 43 Avoid guest-triggerable panics in BAR notify handler. Guest MMIO operations on BAR1 can trigger three distinct panics:
This allows guests to DoS the VMM process. 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: junyu0312/rust-vm
Length of output: 3961
🏁 Script executed:
Repository: junyu0312/rust-vm
Length of output: 183
🏁 Script executed:
Repository: junyu0312/rust-vm
Length of output: 1225
🏁 Script executed:
Repository: junyu0312/rust-vm
Length of output: 183
🏁 Script executed:
Repository: junyu0312/rust-vm
Length of output: 1074
size_ofis not imported and will fail compilation.Lines 65 and 77 use
size_of::<...>()without importing it. Add the required import statement.Proposed fix
use std::sync::Arc; +use std::mem::size_of; use std::sync::Mutex;🤖 Prompt for AI Agents