Skip to content

Validate nested iref reference sizes - #219

Open
kixelated wants to merge 2 commits into
mainfrom
codex/issue-179-iref
Open

Validate nested iref reference sizes#219
kixelated wants to merge 2 commits into
mainfrom
codex/issue-179-iref

Conversation

@kixelated

Copy link
Copy Markdown
Owner

Split from #199. Refs #179.

What changed

  • Validate each nested iref box size before slicing its body.
  • Decode each reference only within its declared box body.
  • Reject undersized, oversized, and trailing nested reference data with Error::InvalidSize.
  • Add regression tests for lengths smaller than the header and larger than the enclosing body.

Why

Nested box lengths are attacker-controlled. The previous decoder subtracted and sliced them without bounds checks, which could underflow, panic, or decode across box boundaries.

Impact

Malformed iref data now returns a normal parse error while valid references continue to decode unchanged.

Validation

  • cargo fmt --all -- --check
  • cargo test --all-features (252 unit tests and 3 doctests passed)
  • cargo clippy --all-targets --all-features -- -D warnings
  • git diff --check main...HEAD

@bradh bradh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. A test for correct decoding would be a useful follow-up.

@bradh
bradh marked this pull request as ready for review July 31, 2026 10:44
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

decode_body_ext now decodes each nested reference box from a bounded body. It validates declared lengths against the containing input and rejects lengths smaller than the box header or larger than the available body. Version 0 and version 1 fields use the bounded body. The decoder returns Error::InvalidSize when bytes remain after nested decoding. Tests cover oversized and undersized nested boxes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: validating nested iref reference sizes.
Description check ✅ Passed The description directly explains the size validation changes, security rationale, tests, and validation results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-179-iref

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@bradh

bradh commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/meta/iref.rs`:
- Around line 33-34: In the nested-reference parsing loop around u32::decode in
src/meta/iref.rs, check buf.remaining() < 4 before decoding the length and
return Error::InvalidSize for incomplete length fragments. Add regression
coverage for a single trailing byte and preserve normal decoding when at least
four bytes remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 142871e2-dd1a-4881-9303-075f30a5fbe2

📥 Commits

Reviewing files that changed from the base of the PR and between fa3ce44 and 5494585.

📒 Files selected for processing (1)
  • src/meta/iref.rs

Comment thread src/meta/iref.rs
Comment on lines +33 to +34
while buf.has_remaining() {
let box_len = u32::decode(buf)? as usize;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the changed decoder before inspecting the primitive Decode implementation.
ast-grep outline src/meta/iref.rs --items all

# Verify the error path used by primitive u32 decoding and locate related tests.
rg -n -C 4 'impl\s+Decode\s+for\s+u32|u32::decode|OutOfBounds|InvalidSize' src
rg -n -C 4 'oversized_nested_reference|nested_reference_smaller_than_header' src/meta/iref.rs

Repository: kixelated/mp4-atom

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the relevant iref decoder and tests.
sed -n '1,190p' src/meta/iref.rs

# Read the exact primitive decoding implementations.
sed -n '1,125p' src/coding.rs

# Read Error enum.
sed -n '1,60p' src/error.rs

# Check current test coverage for small trailing bytes.
rg -n -C 3 '1|2|3|trailing|smaller_than_header|nested' src/meta/iref.rs

# Standalone parser for the exact inputs in the loop.
python3 - <<'PY'
from struct import unpack
inputs = {
    "1 byte trailing": b"\x00",
    "2 byte trailing": b"\x00\x00",
    "3 byte trailing": b"\x00\x00\x00",
}
expected = "Out of bounds"
for name, payload in inputs.items():
    error = None
    if len(payload) < 4:
        error = "Out of bounds"
    print(name, "→", error if error else "valid")
print("u32 primitive requires 4 bytes, so 1-, 2-, 3-byte remainders cannot be decoded before size check.")
PY

Repository: kixelated/mp4-atom

Length of output: 14487


Return Error::InvalidSize for one-byte nested length fragments.

u32::decode(buf) returns Error::OutOfBounds when the buffer has fewer than four bytes, so one remaining byte now leaves the malformed nested reference length error-handling contract inconsistent. Add a guard for buf.remaining() < 4 before decoding box_len and add regression tests for a single trailing byte.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/meta/iref.rs` around lines 33 - 34, In the nested-reference parsing loop
around u32::decode in src/meta/iref.rs, check buf.remaining() < 4 before
decoding the length and return Error::InvalidSize for incomplete length
fragments. Add regression coverage for a single trailing byte and preserve
normal decoding when at least four bytes remain.

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.

2 participants