T09 · Insecure Skill Coding Practices
- Location
SKILL.md:58- Finding
Unbounded UART Interrupt Buffer Write
- Content
View full analysis
SR & USART_SR_RXNE) { rx_buf[rx_len++] = USART->DR; } } ``` ### Technical Analysis The UART interrupt handler writes each received byte into the fixed-size, 64-byte `rx_buf` array without checking whether `rx_len` remains within the array bounds. After 64 bytes have been received, subsequent interrupts write beyond the end of `rx_buf`. Because `rx_len` is an 8-bit integer, it does not prevent the overflow; instead, it continues through values up to 255 before wrapping to zero. This permits extensive corruption of memory adjacent to the buffer. The exact consequences depend on the firmware memory layout. Adjacent global variables, state flags, pointers, or control data may be overwritten. On memory-constrained embedded systems without memory protection, this can cause deterministic crashes or potentially influence control flow. ### Attack Path 1. An attacker obtains physical or remote access to the UART input. 2. The attacker continuously sends more than 64 bytes. 3. Each byte causes `USART1_IRQHandler` to execute. 4. Once `rx_len` reaches 64, `rx_buf[rx_len++]` writes outside the allocated array. 5. Further input corrupts adjacent memory until the counter wraps. 6. Depending on the overwritten data, the device may crash, enter an unsafe state, or execute unintended control flow. ### Impact Assessment An attacker able to provide UART input can cause denial of service and memory corruption within the firmware. If security-sensitive state, function pointers, return-related data, or other control structures are reachable from the buffer, exploitation could potentially result in arbitrary behavior at the firmware's privilege level. The scope is limited to ...[truncated 201 chars]- Remediation
View remediation
SR & USART_SR_RXNE) { uint8_t received = (uint8_t)USART->DR; if (rx_len < RX_BUF_SIZE) { rx_buf[rx_len++] = received; } else { /* Record overflow and safely discard or reset the frame. */ rx_len = 0; } } } ``` For continuous streams, use a bounded ring buffer with separate producer and consumer indexes. Define an explicit overflow policy, such as dropping the newest byte, dropping the oldest byte, or rejecting the current frame. Ensure indexes are updated atomically when shared between interrupt and application contexts. The firmware should also: - Reset receive state at validated frame boundaries. - Track and report overflow events. - Apply maximum frame-size limits before reception begins. - Use fuzz testing and long-stream tests to verify that malformed or continuous UART traffic cannot write outside the buffer. ]]>
