From 0095556847818887b4ced104a889c7b5461657af Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Thu, 10 Apr 2025 13:50:42 +0200 Subject: [PATCH] pci: gracefully handle devices that return 0xff as a capability pointer If a device returns 0xff as a capability pointer bad things happen. The code before the previous commits would crash in debug builds due to integer overflow. With the two lowest bits masked out, it sends the code into an endless loop. Be more robust by at least handling the case where the capability appears to point to itself. Signed-off-by: Julian Stecklina --- pci/src/vfio.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pci/src/vfio.rs b/pci/src/vfio.rs index 75361347a..fe4e10da4 100644 --- a/pci/src/vfio.rs +++ b/pci/src/vfio.rs @@ -897,8 +897,15 @@ impl VfioCommon { if PciCapabilityId::from(cap_id) == PciCapabilityId::MsiX { return Some(cap_next as usize); } else { - cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into()) + let cap_ptr = self.vfio_wrapper.read_config_byte((cap_next + 1).into()) & PCI_CONFIG_CAPABILITY_PTR_MASK; + + // See parse_capabilities below for an explanation. + if cap_ptr != cap_next { + cap_next = cap_ptr; + } else { + break; + } } } @@ -950,7 +957,12 @@ impl VfioCommon { let cap_next = self.vfio_wrapper.read_config_byte((cap_iter + 1).into()) & PCI_CONFIG_CAPABILITY_PTR_MASK; - if cap_next == 0 { + + // Break out of the loop, if we either find the end or we have a broken device. This + // doesn't handle all cases where a device might send us in a loop here, but it + // handles case of a device returning 0xFF instead of implementing a real + // capabilities list. + if cap_next == 0 || cap_next == cap_iter { break; }