mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-11 04:26:38 +00:00
devices: pci: enforce minimum valid BAR sizes
PCI BARs have a minimum size based on the number of bits reserved for the type bitfield, which is stored in the low bits of each BAR. The minimum size is derived from the number of bits used to store the type: 2 bits (4-byte minimum) for I/O bars and 4 bits (16-byte minimum) for memory BARs. Previously, since the minimum size was not enforced, callers could create invalid configurations that would allow the guest to overwrite the type bits of the BARs. Luckily, this only happened in the unit tests, which are fixed in this change. BUG=None TEST=cargo test -p devices Change-Id: I30d65485254b49655c9ad7bec51e43533fe2c01d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2300692 Reviewed-by: Dylan Reid <dgreid@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
36b2a0df71
commit
de06f15777
1 changed files with 75 additions and 7 deletions
|
@ -15,7 +15,9 @@ const STATUS_REG: usize = 1;
|
|||
const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
|
||||
const BAR0_REG: usize = 4;
|
||||
const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
|
||||
const BAR_IO_MIN_SIZE: u64 = 4;
|
||||
const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
|
||||
const BAR_MEM_MIN_SIZE: u64 = 16;
|
||||
const NUM_BAR_REGS: usize = 6;
|
||||
const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
|
||||
const FIRST_CAPABILITY_OFFSET: usize = 0x40;
|
||||
|
@ -199,7 +201,7 @@ pub struct PciBarConfiguration {
|
|||
prefetchable: PciBarPrefetchable,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
BarAddressInvalid(u64, u64),
|
||||
BarAlignmentInvalid(u64, u64),
|
||||
|
@ -370,6 +372,10 @@ impl PciConfiguration {
|
|||
/// (i.e, region size must be power of two, register not already used). Returns 'None' on
|
||||
/// failure all, `Some(BarIndex)` on success.
|
||||
pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
|
||||
if config.reg_idx >= NUM_BAR_REGS {
|
||||
return Err(Error::BarInvalid(config.reg_idx));
|
||||
}
|
||||
|
||||
if self.bar_used[config.reg_idx] {
|
||||
return Err(Error::BarInUse(config.reg_idx));
|
||||
}
|
||||
|
@ -378,8 +384,14 @@ impl PciConfiguration {
|
|||
return Err(Error::BarSizeInvalid(config.size));
|
||||
}
|
||||
|
||||
if config.reg_idx >= NUM_BAR_REGS {
|
||||
return Err(Error::BarInvalid(config.reg_idx));
|
||||
let min_size = if config.region_type == PciBarRegionType::IORegion {
|
||||
BAR_IO_MIN_SIZE
|
||||
} else {
|
||||
BAR_MEM_MIN_SIZE
|
||||
};
|
||||
|
||||
if config.size < min_size {
|
||||
return Err(Error::BarSizeInvalid(config.size));
|
||||
}
|
||||
|
||||
if config.addr % config.size != 0 {
|
||||
|
@ -711,7 +723,7 @@ mod tests {
|
|||
cfg.add_pci_bar(
|
||||
&PciBarConfiguration::new(
|
||||
0,
|
||||
0x4,
|
||||
0x10,
|
||||
PciBarRegionType::Memory64BitRegion,
|
||||
PciBarPrefetchable::NotPrefetchable,
|
||||
)
|
||||
|
@ -725,7 +737,7 @@ mod tests {
|
|||
);
|
||||
assert_eq!(cfg.get_bar_addr(0), 0x01234567_89ABCDE0);
|
||||
assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
|
||||
assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFFC);
|
||||
assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -744,7 +756,7 @@ mod tests {
|
|||
cfg.add_pci_bar(
|
||||
&PciBarConfiguration::new(
|
||||
0,
|
||||
0x4,
|
||||
0x10,
|
||||
PciBarRegionType::Memory32BitRegion,
|
||||
PciBarPrefetchable::NotPrefetchable,
|
||||
)
|
||||
|
@ -757,7 +769,7 @@ mod tests {
|
|||
Some(PciBarRegionType::Memory32BitRegion)
|
||||
);
|
||||
assert_eq!(cfg.get_bar_addr(0), 0x12345670);
|
||||
assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
|
||||
assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -788,4 +800,60 @@ mod tests {
|
|||
assert_eq!(cfg.get_bar_addr(0), 0x1230);
|
||||
assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_pci_bar_invalid_size() {
|
||||
let mut cfg = PciConfiguration::new(
|
||||
0x1234,
|
||||
0x5678,
|
||||
PciClassCode::MultimediaController,
|
||||
&PciMultimediaSubclass::AudioController,
|
||||
Some(&TestPI::Test),
|
||||
PciHeaderType::Device,
|
||||
0xABCD,
|
||||
0x2468,
|
||||
);
|
||||
|
||||
// I/O BAR with size 2 (too small)
|
||||
assert_eq!(
|
||||
cfg.add_pci_bar(
|
||||
&PciBarConfiguration::new(
|
||||
0,
|
||||
0x2,
|
||||
PciBarRegionType::IORegion,
|
||||
PciBarPrefetchable::NotPrefetchable,
|
||||
)
|
||||
.set_address(0x1230),
|
||||
),
|
||||
Err(Error::BarSizeInvalid(0x2))
|
||||
);
|
||||
|
||||
// I/O BAR with size 3 (not a power of 2)
|
||||
assert_eq!(
|
||||
cfg.add_pci_bar(
|
||||
&PciBarConfiguration::new(
|
||||
0,
|
||||
0x3,
|
||||
PciBarRegionType::IORegion,
|
||||
PciBarPrefetchable::NotPrefetchable,
|
||||
)
|
||||
.set_address(0x1230),
|
||||
),
|
||||
Err(Error::BarSizeInvalid(0x3))
|
||||
);
|
||||
|
||||
// Memory BAR with size 8 (too small)
|
||||
assert_eq!(
|
||||
cfg.add_pci_bar(
|
||||
&PciBarConfiguration::new(
|
||||
0,
|
||||
0x8,
|
||||
PciBarRegionType::Memory32BitRegion,
|
||||
PciBarPrefetchable::NotPrefetchable,
|
||||
)
|
||||
.set_address(0x12345670),
|
||||
),
|
||||
Err(Error::BarSizeInvalid(0x8))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue