Skip to content

fix: reject/clamp LDF signal bit_width > 64 to prevent UB in decode() - #25

Open
SoundMatt wants to merge 1 commit into
mainfrom
fix/ldf-bit-width-ub
Open

fix: reject/clamp LDF signal bit_width > 64 to prevent UB in decode()#25
SoundMatt wants to merge 1 commit into
mainfrom
fix/ldf-bit-width-ub

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

lin::ldf::DB::decode() has an unclamped bit-shift for LDF signals with
bit_width > 64 — undefined behavior (aborts under UBSan), reachable via a
malformed/crafted .ldf file plus a decode() call against a >8-byte
buffer.

  • parse_signals() now rejects (skips) any signal whose declared
    bit_width is outside [1, 64].
  • decode() additionally clamps its own loop bound to [0, 64] as defense
    in depth, since DB's storage is public and a Signal can be
    constructed directly without going through the text parser.

Closes #18

Test plan

  • ctest — 174/174 pass (3 new regression tests: parser-level rejection
    of bit_width 128 and 0, plus a decode()-level defense-in-depth
    test that directly constructs a DB/Signal with bit_width = 200
    bypassing the parser, and confirms no UB/crash and a correctly
    clamped result)
  • ASan+UBSan build — 178/178 pass (full suite, includes the new tests)
  • relay conform --strict / relay interop --protocol LIN — both PASS

lin::ldf::DB::decode() shifts a uint64_t by up to bit_width - 1 bits
(`1ULL << i`) with no upper bound on the LDF-declared bit_width. LDF
signals with bit_width > 64 (unconstrained int, no range check in
parse_signals()) trigger a shift-by->=64, which is undefined behavior
and aborts under UBSan.

Reaching the actual UB requires decode()'s data argument to exceed 8
bytes, which is a normal, unbounded std::vector<uint8_t>& — a
malformed or crafted .ldf file can therefore crash any process that
parses it and later decodes an oversized frame against it.

Fixes:
- parse_signals() now rejects (skips) any signal whose parsed
  bit_width falls outside [1, 64], consistent with how the parser
  already skips other malformed signal lines rather than storing bad
  data.
- decode() additionally clamps its own loop bound to [0, 64] as
  defense in depth, since DB's storage members are public and a
  Signal can be constructed directly by a caller that bypasses the
  text parser entirely.

Closes #18

Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.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.

lin::ldf::DB::decode() has an unclamped bit-shift (UB, aborts under UBSan) for LDF signals with bit_width > 64

1 participant