diff --git a/drivers/usb/xhcid/src/xhci/extended.rs b/drivers/usb/xhcid/src/xhci/extended.rs index 00ab6f2f1b..e15ec2ec75 100644 --- a/drivers/usb/xhcid/src/xhci/extended.rs +++ b/drivers/usb/xhcid/src/xhci/extended.rs @@ -223,16 +223,24 @@ pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT: u8 = 0; impl SupportedProtoCap { pub unsafe fn protocol_speeds(&self) -> &[ProtocolSpeed] { + // xHCI spec §7.2: PSIC is a 4-bit field (max 15). + // xHCI spec §4.16.1.1: PSIV may be 0-15, so max 15 ProtocolSpeed entries. + // Cap at 15 to prevent OOB reads from buggy controllers. + // Cross-referenced with Linux 7.1 drivers/usb/host/xhci-mem.c + // xhci_create_port_array() which uses kcalloc_node() with the + // bounded PSIC count. + let max_psic = (self.psic() as usize).min(15); slice::from_raw_parts( &self.protocol_speeds as *const u8 as *const _, - self.psic() as usize, + max_psic, ) } pub unsafe fn protocol_speeds_mut(&mut self) -> &mut [ProtocolSpeed] { // XXX: Variance really is annoying sometimes. + let max_psic = (self.psic() as usize).min(15); slice::from_raw_parts_mut( &self.protocol_speeds as *const u8 as *mut u8 as *mut _, - self.psic() as usize, + max_psic, ) } pub fn rev_minor(&self) -> u8 {