Skip to content

Commit e5f308c

Browse files
gaojiaqi7jyao1
authored andcommitted
virtio-pci: fix potential misaligned issue
Misaligned read or write to physical memory or MMIO may cause unexpected errors. Signed-off-by: Jiaqi Gao <[email protected]>
1 parent b546154 commit e5f308c

File tree

7 files changed

+146
-83
lines changed

7 files changed

+146
-83
lines changed

src/devices/pci/src/config.rs

Lines changed: 81 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -95,20 +95,20 @@ pub fn pci_cf8_read8(bus: u8, device: u8, fnc: u8, reg: u8) -> u8 {
9595
}
9696
}
9797

98-
fn get_device_details(bus: u8, device: u8, func: u8) -> (u16, u16) {
99-
let config_data = ConfigSpacePciEx::read::<u32>(bus, device, func, 0);
100-
(
98+
fn get_device_details(bus: u8, device: u8, func: u8) -> Result<(u16, u16)> {
99+
let config_data = ConfigSpacePciEx::read::<u32>(bus, device, func, 0)?;
100+
Ok((
101101
(config_data & 0xffff) as u16,
102102
((config_data & 0xffff0000) >> 0x10) as u16,
103-
)
103+
))
104104
}
105105

106106
pub fn find_device(vendor_id: u16, device_id: u16) -> Option<(u8, u8, u8)> {
107107
const MAX_DEVICES: u8 = 32;
108108
const INVALID_VENDOR_ID: u16 = 0xffff;
109109

110110
for device in 0..MAX_DEVICES {
111-
if (vendor_id, device_id) == get_device_details(0, device, 0) {
111+
if (vendor_id, device_id) == get_device_details(0, device, 0).ok()? {
112112
return Some((0, device, 0));
113113
}
114114
if vendor_id == INVALID_VENDOR_ID {
@@ -191,12 +191,12 @@ impl ConfigSpace {
191191
}
192192

193193
/// Get vendor_id and device_id
194-
pub fn get_device_details(bus: u8, device: u8, func: u8) -> (u16, u16) {
195-
let config_data = ConfigSpacePciEx::read::<u32>(bus, device, func, 0);
196-
(
194+
pub fn get_device_details(bus: u8, device: u8, func: u8) -> Result<(u16, u16)> {
195+
let config_data = ConfigSpacePciEx::read::<u32>(bus, device, func, 0)?;
196+
Ok((
197197
(config_data & 0xffff) as u16,
198198
((config_data & 0xffff0000) >> 0x10) as u16,
199-
)
199+
))
200200
}
201201

202202
fn get_config_address(bus: u8, device: u8, func: u8, offset: u8) -> ConfigAddress {
@@ -215,49 +215,73 @@ impl ConfigSpace {
215215
pub struct ConfigSpacePciEx;
216216
impl ConfigSpacePciEx {
217217
#[cfg(not(feature = "fuzz"))]
218-
pub fn read<T: Copy + Clone>(bus: u8, device: u8, func: u8, offset: u16) -> T {
218+
pub fn read<T: Copy + Clone>(bus: u8, device: u8, func: u8, offset: u16) -> Result<T> {
219219
let addr = PCI_EX_BAR_BASE_ADDRESS
220220
+ ((bus as u64) << 20)
221221
+ ((device as u64) << 15)
222222
+ ((func as u64) << 12)
223223
+ offset as u64;
224224

225+
if addr % align_of::<T>() as u64 != 0 {
226+
return Err(PciError::Misaligned);
227+
}
225228
#[cfg(feature = "iocall")]
226229
unsafe {
227-
core::ptr::read_volatile(addr as *const T)
230+
Ok(core::ptr::read_volatile(addr as *const T))
228231
}
229232
#[cfg(feature = "tdcall")]
230-
tdx_tdcall::tdx::tdvmcall_mmio_read(addr as usize)
233+
Ok(tdx_tdcall::tdx::tdvmcall_mmio_read(addr as usize))
231234
}
232235
#[cfg(feature = "fuzz")]
233-
pub fn read<T: Copy + Clone>(_bus: u8, _device: u8, _func: u8, offset: u16) -> T {
236+
pub fn read<T: Copy + Clone>(_bus: u8, _device: u8, _func: u8, offset: u16) -> Result<T> {
234237
let base_address = crate::get_fuzz_seed_address();
235238
let address = base_address + offset as u64;
236-
unsafe { core::ptr::read_volatile(address as *const T) }
239+
if address % align_of::<T>() as u64 != 0 {
240+
return Err(PciError::Misaligned);
241+
}
242+
unsafe { Ok(core::ptr::read_volatile(address as *const T)) }
237243
}
238244

239245
#[cfg(not(feature = "fuzz"))]
240-
pub fn write<T: Copy + Clone>(bus: u8, device: u8, func: u8, offset: u16, value: T) {
246+
pub fn write<T: Copy + Clone>(
247+
bus: u8,
248+
device: u8,
249+
func: u8,
250+
offset: u16,
251+
value: T,
252+
) -> Result<()> {
241253
let addr = PCI_EX_BAR_BASE_ADDRESS
242254
+ ((bus as u64) << 20)
243255
+ ((device as u64) << 15)
244256
+ ((func as u64) << 12)
245257
+ offset as u64;
258+
259+
if addr % align_of::<T>() as u64 != 0 {
260+
return Err(PciError::Misaligned);
261+
}
246262
#[cfg(feature = "iocall")]
247263
unsafe {
248-
core::ptr::write_volatile(addr as *mut T, value)
264+
core::ptr::write_volatile(addr as *mut T, value);
249265
}
250266
#[cfg(feature = "tdcall")]
251267
tdx_tdcall::tdx::tdvmcall_mmio_write(addr as *mut T, value);
268+
Ok(())
252269
}
253270

254271
#[cfg(feature = "fuzz")]
255-
pub fn write<T: Copy + Clone>(_bus: u8, _device: u8, _func: u8, offset: u16, value: T) {
256-
unsafe {
257-
let base_address = crate::get_fuzz_seed_address();
258-
let address = base_address + offset as u64;
259-
core::ptr::write_volatile(address as *mut T, value)
272+
pub fn write<T: Copy + Clone>(
273+
_bus: u8,
274+
_device: u8,
275+
_func: u8,
276+
offset: u16,
277+
value: T,
278+
) -> Result<()> {
279+
let base_address = crate::get_fuzz_seed_address();
280+
let address = base_address + offset as u64;
281+
if address % align_of::<T>() as u64 != 0 {
282+
return Err(PciError::Misaligned);
260283
}
284+
unsafe { Ok(core::ptr::write_volatile(address as *mut T, value)) }
261285
}
262286
}
263287

@@ -384,11 +408,11 @@ impl PciDevice {
384408
#[cfg(not(feature = "fuzz"))]
385409
pub fn init(&mut self) -> Result<()> {
386410
let (vendor_id, device_id) =
387-
ConfigSpace::get_device_details(self.bus, self.device, self.func);
411+
ConfigSpace::get_device_details(self.bus, self.device, self.func)?;
388412
self.common_header.vendor_id = vendor_id;
389413
self.common_header.device_id = device_id;
390-
let command = self.read_u16(0x4);
391-
let status = self.read_u16(0x6);
414+
let command = self.read_u16(0x4)?;
415+
let status = self.read_u16(0x6)?;
392416
log::info!(
393417
"PCI Device: {}:{}.{} {:x}:{:x}\nbit \t fedcba9876543210\nstate\t {:016b}\ncommand\t {:016b}\n",
394418
self.bus,
@@ -405,7 +429,7 @@ impl PciDevice {
405429

406430
//0x24 offset is last bar
407431
while current_bar_offset <= 0x24 {
408-
let bar = self.read_u32(current_bar_offset);
432+
let bar = self.read_u32(current_bar_offset)?;
409433

410434
// lsb is 1 for I/O space bars
411435
if bar & 1 == 1 {
@@ -415,11 +439,11 @@ impl PciDevice {
415439
// bits 2-1 are the type 0 is 32-but, 2 is 64 bit
416440
match bar >> 1 & 3 {
417441
0 => {
418-
let size = self.get_bar_size(current_bar_offset);
442+
let size = self.get_bar_size(current_bar_offset)?;
419443

420444
let addr = if size > 0 {
421445
let addr = alloc_mmio32(size)?;
422-
self.set_bar_addr(current_bar_offset, addr);
446+
self.set_bar_addr(current_bar_offset, addr)?;
423447
addr
424448
} else {
425449
bar
@@ -432,15 +456,15 @@ impl PciDevice {
432456
2 => {
433457
self.bars[current_bar].bar_type = PciBarType::MemorySpace64;
434458

435-
let mut size = self.get_bar_size(current_bar_offset) as u64;
459+
let mut size = self.get_bar_size(current_bar_offset)? as u64;
436460
if size == 0 {
437-
size = (self.get_bar_size(current_bar_offset + 4) as u64) << 32;
461+
size = (self.get_bar_size(current_bar_offset + 4)? as u64) << 32;
438462
}
439463

440464
let addr = if size > 0 {
441465
let addr = alloc_mmio64(size)?;
442-
self.set_bar_addr(current_bar_offset, addr as u32);
443-
self.set_bar_addr(current_bar_offset + 4, (addr >> 32) as u32);
466+
self.set_bar_addr(current_bar_offset, addr as u32)?;
467+
self.set_bar_addr(current_bar_offset + 4, (addr >> 32) as u32)?;
444468
addr
445469
} else {
446470
bar as u64
@@ -461,7 +485,7 @@ impl PciDevice {
461485
self.write_u16(
462486
0x4,
463487
(PciCommand::IO_SPACE | PciCommand::MEMORY_SPACE | PciCommand::BUS_MASTER).bits(),
464-
);
488+
)?;
465489
for bar in &self.bars {
466490
log::info!("Bar: type={:?} address={:x}\n", bar.bar_type, bar.address);
467491
}
@@ -472,18 +496,18 @@ impl PciDevice {
472496
#[cfg(feature = "fuzz")]
473497
pub fn init(&mut self) -> Result<()> {
474498
let (vendor_id, device_id) =
475-
ConfigSpace::get_device_details(self.bus, self.device, self.func);
499+
ConfigSpace::get_device_details(self.bus, self.device, self.func)?;
476500
self.common_header.vendor_id = vendor_id;
477501
self.common_header.device_id = device_id;
478-
let command = self.read_u16(0x4);
479-
let status = self.read_u16(0x6);
502+
let command = self.read_u16(0x4)?;
503+
let status = self.read_u16(0x6)?;
480504

481505
let mut current_bar_offset = 0x10;
482506
let mut current_bar = 0;
483507

484508
//0x24 offset is last bar
485509
while current_bar_offset <= 0x24 {
486-
let bar = self.read_u32(current_bar_offset);
510+
let bar = self.read_u32(current_bar_offset)?;
487511

488512
// lsb is 1 for I/O space bars
489513
if bar & 1 == 1 {
@@ -493,11 +517,11 @@ impl PciDevice {
493517
// bits 2-1 are the type 0 is 32-but, 2 is 64 bit
494518
match bar >> 1 & 3 {
495519
0 => {
496-
let size = self.read_u32(current_bar_offset);
520+
let size = self.read_u32(current_bar_offset)?;
497521

498522
let addr = if size > 0 {
499523
let addr = alloc_mmio32(size)?;
500-
self.set_bar_addr(current_bar_offset, addr);
524+
self.set_bar_addr(current_bar_offset, addr)?;
501525
addr
502526
} else {
503527
bar
@@ -510,11 +534,11 @@ impl PciDevice {
510534
2 => {
511535
self.bars[current_bar].bar_type = PciBarType::MemorySpace64;
512536

513-
let mut size = self.read_u64(current_bar_offset);
537+
let mut size = self.read_u64(current_bar_offset)?;
514538
let addr = if size > 0 {
515539
let addr = alloc_mmio64(size)?;
516-
self.set_bar_addr(current_bar_offset, addr as u32);
517-
self.set_bar_addr(current_bar_offset + 4, (addr >> 32) as u32);
540+
self.set_bar_addr(current_bar_offset, addr as u32)?;
541+
self.set_bar_addr(current_bar_offset + 4, (addr >> 32) as u32)?;
518542
addr
519543
} else {
520544
bar as u64
@@ -540,56 +564,56 @@ impl PciDevice {
540564
Ok(())
541565
}
542566

543-
fn set_bar_addr(&self, offset: u8, addr: u32) {
544-
self.write_u32(offset, addr);
567+
fn set_bar_addr(&self, offset: u8, addr: u32) -> Result<()> {
568+
self.write_u32(offset, addr)
545569
}
546570

547-
fn get_bar_size(&self, offset: u8) -> u32 {
548-
let restore = self.read_u32(offset);
549-
self.write_u32(offset, u32::MAX);
550-
let size = self.read_u32(offset);
551-
self.write_u32(offset, restore);
571+
fn get_bar_size(&self, offset: u8) -> Result<u32> {
572+
let restore = self.read_u32(offset)?;
573+
self.write_u32(offset, u32::MAX)?;
574+
let size = self.read_u32(offset)?;
575+
self.write_u32(offset, restore)?;
552576

553-
if size == 0 {
577+
Ok(if size == 0 {
554578
size
555579
} else {
556580
!(size & 0xFFFF_FFF0) + 1
557-
}
581+
})
558582
}
559583

560-
pub fn read_u64(&self, offset: u8) -> u64 {
584+
pub fn read_u64(&self, offset: u8) -> Result<u64> {
561585
ConfigSpacePciEx::read::<u64>(self.bus, self.device, self.func, offset as u16)
562586
// let low = ConfigSpace::read32(self.bus, self.device, self.func, offset);
563587
// let high = ConfigSpace::read32(self.bus, self.device, self.func, offset + 8);
564588
// (low as u64) & ((high as u64) << 8)
565589
}
566590

567-
pub fn read_u32(&self, offset: u8) -> u32 {
591+
pub fn read_u32(&self, offset: u8) -> Result<u32> {
568592
ConfigSpacePciEx::read::<u32>(self.bus, self.device, self.func, offset as u16)
569593
// ConfigSpace::read32(self.bus, self.device, self.func, offset)
570594
}
571595

572-
pub fn read_u16(&self, offset: u8) -> u16 {
596+
pub fn read_u16(&self, offset: u8) -> Result<u16> {
573597
ConfigSpacePciEx::read::<u16>(self.bus, self.device, self.func, offset as u16)
574598
// ConfigSpace::read16(self.bus, self.device, self.func, offset)
575599
}
576600

577-
pub fn read_u8(&self, offset: u8) -> u8 {
601+
pub fn read_u8(&self, offset: u8) -> Result<u8> {
578602
ConfigSpacePciEx::read::<u8>(self.bus, self.device, self.func, offset as u16)
579603
// ConfigSpace::read8(self.bus, self.device, self.func, offset)
580604
}
581605

582-
pub fn write_u32(&self, offset: u8, value: u32) {
606+
pub fn write_u32(&self, offset: u8, value: u32) -> Result<()> {
583607
ConfigSpacePciEx::write::<u32>(self.bus, self.device, self.func, offset as u16, value)
584608
// ConfigSpace::write32(self.bus, self.device, self.func, offset, value)
585609
}
586610

587-
pub fn write_u16(&self, offset: u8, value: u16) {
611+
pub fn write_u16(&self, offset: u8, value: u16) -> Result<()> {
588612
ConfigSpacePciEx::write::<u16>(self.bus, self.device, self.func, offset as u16, value)
589613
// ConfigSpace::write16(self.bus, self.device, self.func, offset, value)
590614
}
591615

592-
pub fn write_u8(&self, offset: u8, value: u8) {
616+
pub fn write_u8(&self, offset: u8, value: u8) -> Result<()> {
593617
ConfigSpacePciEx::write::<u8>(self.bus, self.device, self.func, offset as u16, value)
594618
// ConfigSpace::write8(self.bus, self.device, self.func, offset, value)
595619
}

src/devices/pci/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ pub fn get_fuzz_seed_address() -> u64 {
2121

2222
pub type Result<T> = core::result::Result<T, PciError>;
2323

24+
#[derive(Debug)]
2425
pub enum PciError {
2526
InvalidParameter,
2627
MmioOutofResource,
2728
InvalidBarType,
29+
Misaligned,
2830
}

src/devices/virtio/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
extern crate alloc;
77
use core::fmt::Display;
88
use mem::MemoryRegionError;
9+
use pci::PciError;
910

1011
pub mod consts;
1112
mod mem;
@@ -47,6 +48,8 @@ pub enum VirtioError {
4748
InvalidRingIndex,
4849
/// Invalid index for ring
4950
InvalidDescriptor,
51+
/// Pci related error
52+
Pci(PciError),
5053
}
5154

5255
impl Display for VirtioError {
@@ -69,6 +72,7 @@ impl Display for VirtioError {
6972
VirtioError::InvalidDescriptorIndex => write!(f, "InvalidDescriptorIndex"),
7073
VirtioError::InvalidRingIndex => write!(f, "InvalidRingIndex"),
7174
VirtioError::InvalidDescriptor => write!(f, "InvalidDescriptor"),
75+
VirtioError::Pci(_) => write!(f, "Pci"),
7276
}
7377
}
7478
}
@@ -79,6 +83,12 @@ impl From<mem::MemoryRegionError> for VirtioError {
7983
}
8084
}
8185

86+
impl From<PciError> for VirtioError {
87+
fn from(e: PciError) -> Self {
88+
VirtioError::Pci(e)
89+
}
90+
}
91+
8292
pub type Result<T = ()> = core::result::Result<T, VirtioError>;
8393

8494
/// Trait to allow separation of transport from block driver

0 commit comments

Comments
 (0)