btintel: fix F22 ECDSA firmware blob out-of-bounds slice panic

CRITICAL F22 from NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md
§3.5: redbear-btusb/src/btintel.rs:178-187 sliced fw_data[644+128..644+224]
and [644+224..644+320] on the ECDSA branch with only 'if fw_data.len() < 644'
bounds-check. A 645..963 byte ECDSA firmware blob would panic with
'range start index 772 out of range for slice of length N'.

Fix: introduce ECDSA_FULL_LEN = ECDSA_HEADER_LEN + 128 + 96 + 96 (= 964)
covering the full ECDSA header (CSS + PKEY + SIG). Update the bounds
check to require fw_data.len() >= ECDSA_FULL_LEN. The payload slice
now starts at ECDSA_FULL_LEN, making the slice operations guaranteed
in-bounds. The error message is updated to print the actual minimum
length (964) instead of the misleading 644.

Also updates the existing ECDSA_HEADER_LEN = 644 constant reference:
the constant is correctly used; the bug was that the check itself
was under-specifying the requirement (only the header start, not
the header end).
This commit is contained in:
2026-07-27 16:24:01 +09:00
parent 092d1b39c3
commit 94c8b51b44
@@ -176,14 +176,23 @@ pub fn firmware_download_commands(fw_data: &[u8]) -> Vec<HciCommand> {
commands.extend(secure_send_commands(FRAGMENT_TYPE_PAYLOAD, payload));
}
CssKeyType::Ecdsa => {
if fw_data.len() < 644 {
warn!("btintel: ECDSA firmware too short ({} bytes)", fw_data.len());
// ECDSA firmware layout: CSS @ 644..772, PKEY @ 772..868,
// SIG @ 868..964. Payload starts at 964. Without the full
// bounds check, a 645..963 byte blob would panic on the
// PKEY/SIG slices.
const ECDSA_FULL_LEN: usize = ECDSA_HEADER_LEN + 128 + 96 + 96;
if fw_data.len() < ECDSA_FULL_LEN {
warn!(
"btintel: ECDSA firmware too short ({} bytes, need {})",
fw_data.len(),
ECDSA_FULL_LEN
);
return commands;
}
commands.extend(secure_send_commands(FRAGMENT_TYPE_CSS, &fw_data[644..644 + 128]));
commands.extend(secure_send_commands(FRAGMENT_TYPE_PKEY, &fw_data[644 + 128..644 + 224]));
commands.extend(secure_send_commands(FRAGMENT_TYPE_SIGNATURE, &fw_data[644 + 224..644 + 320]));
let payload = &fw_data[644 + 320..];
let payload = &fw_data[ECDSA_FULL_LEN..];
commands.extend(secure_send_commands(FRAGMENT_TYPE_PAYLOAD, payload));
}
CssKeyType::Hybrid => {