Skip to content

fix(cobs): avoid out-of-bounds read in apex_cobs_decode_framed on all-zero input#1

Open
steps-re wants to merge 1 commit into
Neros-Technologies:mainfrom
steps-re:fix/cobs-decode-framed-oob-read
Open

fix(cobs): avoid out-of-bounds read in apex_cobs_decode_framed on all-zero input#1
steps-re wants to merge 1 commit into
Neros-Technologies:mainfrom
steps-re:fix/cobs-decode-framed-oob-read

Conversation

@steps-re

@steps-re steps-re commented Jul 7, 2026

Copy link
Copy Markdown

Summary

apex_cobs_decode_framed() reads one byte past the end of input when the buffer is entirely 0x00.

Details

The leading-delimiter skip loop dereferences input[i] before the bound check:

while (input[i] == 0x00 && i < length) i++;

&& evaluates left-to-right, so on an all-zero buffer i walks up to length and input[length] is read before the loop terminates. An all-zeros buffer is a realistic input on a UART wire (idle line held low, electrical noise, or a run of the 0x00 bytes APEX uses as frame delimiters), and this is a public API (apex_cobs.h) consuming bytes straight off the wire, so the out-of-bounds read is reachable from malformed/adversarial input.

Fix

Swap the operands so the bound is checked first. No behavior change on any valid input.

Verification

  • Builds clean with the repo Makefile (-std=c99 -Wall -Wextra -Wpedantic), no new warnings.
  • AddressSanitizer reproducer (heap buffer of exactly length zero bytes): beforeheap-buffer-overflow READ of size 1 in the skip loop; after → no error, returns APEX_ERR_MALFORMED.
  • Round-trip regression (apex_cobs_encode_framedapex_cobs_decode_framed) under ASan still passes.

The sibling trailing-delimiter loop is already safe (bounded below by i). Note: test_cobs.cc doesn't currently exercise the _framed helpers — happy to add a DecodeFramedAllZeros case if you point me at the gtest vendor path.

…-zero input

The leading-delimiter skip loop tested `input[i]` before `i < length`:

    while (input[i] == 0x00 && i < length) i++;

Because `&&` short-circuits left-to-right, `input[i]` is read before the
bound is checked. When the input is entirely 0x00 (an idle/low UART line, or
a run of frame delimiters — both plausible on a real wire), `i` advances to
`length` and `input[length]` is read one byte past the buffer before the
loop exits. AddressSanitizer confirms a heap-buffer-overflow READ here.

Swap the operands so the bound is checked first:

    while (i < length && input[i] == 0x00) i++;

Behavior is otherwise unchanged: an all-zero buffer is still rejected as
APEX_ERR_MALFORMED, and valid framed messages round-trip as before. The
sibling trailing-delimiter loop is already safe (its index is bounded below
by `i`).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Mike German <mike@stepsventures.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant