Skip to content

fix(#76)!: checked size arithmetic in MatterBuilder variable-size parse#77

Merged
joeldsouzax merged 1 commit into
mainfrom
fix/76-checked-size-arithmetic
Jul 4, 2026
Merged

fix(#76)!: checked size arithmetic in MatterBuilder variable-size parse#77
joeldsouzax merged 1 commit into
mainfrom
fix/76-checked-size-arithmetic

Conversation

@joeldsouzax

Copy link
Copy Markdown
Contributor

Closes #76.

Problem

MatterBuilder's variable-size parse paths computed the frame size from the attacker-controlled decoded soft size using unchecked arithmetic, violating the arithmetic-safety mandatory rule:

  • from_qualified_base64 (:132) and from_qualified_base2 (:263): fs = (size * 4) + cs
  • from_qualified_base2 (:265): bfs = (fs * 3).div_ceil(4)

size comes from decode_int(soft). In debug this panics on overflow (DoS on untrusted input, same class as the 5BAA panic fixed in #74); in release it wraps to a small bogus fs, and the subsequent stream.len() < fs check then passes, slicing a truncated frame that parses as valid (silently-wrong parse — exactly what the rule warns about). The adjacent :276 already used .checked_add, so these were inconsistent oversights.

Fix

Extract the three sites into checked helpers in builder.rs:

  • compute_full_size(size, cs)checked_mul(4) + checked_add(cs)
  • compute_qb2_byte_size(fs)checked_mul(3) then div_ceil(4)

Both return a new typed ValidationError::SizeOverflow on overflow (distinct failure domain from IncorrectRawSize). Call sites propagate via ?.

Reachability (resolves the issue's open question)

Latent, not reachable through the parse API today. Variable-size codes cap the soft field at ss=4 (SizeType::Large), so size ≤ 64⁴−1 = 2²⁴−1; then size*4 ≈ 2²⁶ fits even 32-bit usize (wasm32). Reaching overflow needs size ≥ 2³⁰ (a ≥5-char soft field no current code has). Fixed as a Mandatory-Rule violation + defense-in-depth for any future wider soft field.

Because the overflow is unreachable via from_qualified_base64/base2, there is no fuzz-corpus seed to add — the tests probe the checked helpers directly instead.

Tests (TDD)

  • RED: 3 overflow tests panicked with "attempt to multiply with overflow" against the bare arithmetic; 2 in-range tests passed.
  • GREEN: after checked_*, all 5 pass (SizeOverflow returned), plus 61/61 builder+error tests and the full nix flake check gate.

Breaking change

ValidationError gains a SizeOverflow variant. As the enum is public and not #[non_exhaustive], downstream exhaustive match must handle it — MINOR under the 0.x SemVer convention. Noted in CHANGELOG.

Verification

nix flake check — all checks green (clippy, fmt, taplo, audit, deny, nextest, doctest, wasm, no_std, fuzz-replay).

🤖 Generated with Claude Code

The qb64/qb2 variable-size parse paths computed the frame size from the
attacker-controlled decoded soft `size` with unchecked arithmetic
(`fs = size * 4 + cs`, `bfs = ceil(fs * 3 / 4)`), violating the
arithmetic-safety mandatory rule. In debug this panics on overflow
(DoS on untrusted input); in release it wraps to a small bogus `fs` that
then slices a truncated frame as valid (silently-wrong parse).

Extract the three sites (from_qualified_base64 :132, from_qualified_base2
:263/:265) into checked helpers `compute_full_size` / `compute_qb2_byte_size`
using checked_mul/checked_add, returning a new typed
`ValidationError::SizeOverflow` on overflow.

BREAKING CHANGE: `ValidationError` gains a `SizeOverflow` variant; as the
enum is public and not `#[non_exhaustive]`, downstream exhaustive matches
must handle it. MINOR under the 0.x SemVer convention.

Latent, not reachable through the parse API today: variable codes cap the
soft field at ss=4, so size <= 2^24-1 and size*4 fits even 32-bit usize
(wasm32). Fixed as a rule violation + defense-in-depth. Tests probe the
checked helpers directly (RED: bare arithmetic panics on overflow; GREEN:
typed Err) since the overflow is unreachable via from_qualified_base64/base2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codspeed-hq

codspeed-hq Bot commented Jul 4, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 21 untouched benchmarks


Comparing fix/76-checked-size-arithmetic (7b2bb3e) with main (f0e77b5)

Open in CodSpeed

@joeldsouzax joeldsouzax merged commit 1c62ce8 into main Jul 4, 2026
6 checks passed
@joeldsouzax joeldsouzax deleted the fix/76-checked-size-arithmetic branch July 4, 2026 20:09
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.

Unchecked size arithmetic in MatterBuilder variable-size parse (size * 4 overflow, wasm32/32-bit)

1 participant