What changed, and why it matters
This commit fixes a bug in the firmware that talks to a Bluetooth chip over a serial (UART) link. If a malformed or truncated message shorter than 5 bytes reached the validation step, the code would subtract 5 from the message length. Because the length was stored as an unsigned number, the result wrapped around to a very large value instead of becoming negative. That large value could then be used to read memory outside the intended buffer, potentially leaking data or causing the device to behave unpredictably. The fix rejects any frame shorter than 5 bytes before doing the subtraction.
Treat as a security fix and include in release notes. Verify whether the UART interface is reachable from untrusted input (e.g., over USB, BLE, or physical access) and assess whether the out-of-bounds read could be escalated to information disclosure or denial of service. Consider fuzzing the serial-link parser with truncated and malformed frames.
Security signals we found
Integer underflow in length validation
Out-of-bounds read from attacker-influenced length
Missing minimum-size bounds check on parsed frame
Embedded serial/UART protocol parser hardening
Evidence from the diff
In src/da14531/da14531_protocol.c, the serial-link parser validates a frame by computing frame_len - 5 (type byte + 2-byte length + 2-byte CRC). If frame_len is less than 5, the unsigned subtraction underflows to a large value, and subsequent length/CRC handling reads out of bounds from self->frame[]. The patch adds an explicit guard: if self->frame_len < 5, the frame is logged, dropped, and the parser returns to READING state. This is a classic integer underflow leading to out-of-bounds read in an embedded firmware parser.
Changed components
src/da14531/da14531_protocol.cDA14531 serial-link parserBitBox02 Bluetooth/UART communication stackInspect captured patch +10 / −0
diff --git a/src/da14531/da14531_protocol.c b/src/da14531/da14531_protocol.c
index 8480681..86fb193 100644
--- a/src/da14531/da14531_protocol.c
+++ b/src/da14531/da14531_protocol.c
@@ -275,6 +275,16 @@ static struct da14531_protocol_frame* _serial_link_in_poll(
// util_log("frame len so far: %d", self->frame_len);
} break;
case SERIAL_LINK_STATE_CHECK: {
+ // Frame format: [type:1][len:2][payload:len][crc:2].
+ // Guard against `frame_len - 5` underflow and out-of-bounds reads below.
+ if (self->frame_len < 5) {
+ util_log(
+ "da14531: ERROR, short frame len %u, dropped frame", (unsigned)self->frame_len);
+ self->state = SERIAL_LINK_STATE_READING;
+ self->frame_len = 0;
+ return NULL;
+ }
+
// bytes with index 1-2 are the length
uint16_t len = *((uint16_t*)&self->frame[1]);
Why this scored 68/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.