xhcid: cap protocol_speeds slice at max 15 (xHCI spec limit)

The PSIC field in xHCI Supported Protocol Capability is 4 bits,
so its value is 0-15. Using an unbounded psic() for slicing
risks OOB reads if a buggy controller reports 15 but the actual
data is shorter (or absent).

Cap at 15 per xHCI spec §7.2 and §4.16.1.1. This matches Linux 7.1
xhci_create_port_array() which uses kcalloc_node with the count
for proper allocation.
This commit is contained in:
Red Bear OS
2026-07-08 22:44:11 +03:00
parent 263950aefa
commit 7f7f29b4d4
+10 -2
View File
@@ -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 {