LDataFrame::parse panics with a slice-bounds error when it receives a cEMI L_Data frame that has a data TPCI but npdu_length = 1, i.e. a 6-bit encoded APCI payload (such as a plain DPT 1 GroupValueWrite) where the octet count field is 1. We observed such telegrams in traffic from a real KNX/IP gateway. Since this is wire input, the parser should return an error (or an empty payload) instead of panicking — on an embedded target this takes the whole device down.
Reproduction
use knx_pico::protocol::cemi::LDataFrame;
#[test]
fn parse_npdu_length_1_group_write() {
// L_Data.ind: ctrl1, ctrl2, source 1.1.1, dest GA, npdu_length=1,
// TPCI=0x00 (T_Data_Group), APCI=0x81 (GroupValueWrite, 6-bit value "on")
let frame = [0xBC, 0xE0, 0x11, 0x01, 0x0A, 0x03, 0x01, 0x00, 0x81];
let parsed = LDataFrame::parse(&frame);
assert!(parsed.is_ok());
}
thread 'parse_npdu_length_1_group_write' panicked at src/protocol/cemi.rs:482:29:
slice index starts at 9 but ends at 8
Analysis
In LDataFrame::parse (src/protocol/cemi.rs):
- for a data TPCI,
data_start is set to 9 (TPCI and APCI bytes consumed),
npdu_end = 7 + npdu_length, which is 8 when npdu_length = 1,
- the only bounds check is
data.len() < npdu_end, which passes,
&data[data_start..npdu_end] is then &data[9..8] — an inverted range,
which panics.
Suggested fix
Treat npdu_end <= data_start as "no separate data bytes" (the 6-bit value
lives in the APCI byte):
// For 6-bit encoding (npdu_length=1), data is empty (value in APCI)
// For standard encoding, data starts at position 9
let app_data = if npdu_end <= data_start {
&[] // 6-bit encoded, no separate data bytes
} else {
&data[data_start..npdu_end]
};
We carry exactly this fix (plus the regression test above) in our fork:
aimdb-dev@41ef8a3
Happy to open a PR if you'd like.
LDataFrame::parsepanics with a slice-bounds error when it receives a cEMI L_Data frame that has a data TPCI butnpdu_length = 1, i.e. a 6-bit encoded APCI payload (such as a plain DPT 1GroupValueWrite) where the octet count field is 1. We observed such telegrams in traffic from a real KNX/IP gateway. Since this is wire input, the parser should return an error (or an empty payload) instead of panicking — on an embedded target this takes the whole device down.Reproduction
Analysis
In
LDataFrame::parse(src/protocol/cemi.rs):data_startis set to 9 (TPCI and APCI bytes consumed),npdu_end = 7 + npdu_length, which is 8 whennpdu_length = 1,data.len() < npdu_end, which passes,&data[data_start..npdu_end]is then&data[9..8]— an inverted range,which panics.
Suggested fix
Treat
npdu_end <= data_startas "no separate data bytes" (the 6-bit valuelives in the APCI byte):
We carry exactly this fix (plus the regression test above) in our fork:
aimdb-dev@41ef8a3
Happy to open a PR if you'd like.