Skip to content

Binary format fails open: no validation on load, unchecked capacity casts #422

Description

@zharinov

Problem

The binary bytecode format fails open — invalid input loads successfully and panics later:

  1. Module::from_storage (crates/plotnik-bytecode/src/bytecode/module.rs:209) validates magic, version, and total size only. No section-offset bounds checks.
  2. The per-TypeDef data + count bounds validation specified in docs/binary-format/04-types.md is not implemented.
  3. A CRC32 checksum is written into the header at emit time (crates/plotnik-bytecode/src/bytecode/header.rs) and never read at load. Corrupt or truncated bytecode loads without error and panics on first access (confirmed with crafted headers).
  4. Capacity limits are unchecked casts:
    • 255 struct fields silently wrap mod 256 (a 300-capture query passes check and infers 44 fields, exit 0 — confirmed);

    • total_steps is u16, so the > 65535 guard in the emitter is dead code — step addresses wrap before the check runs;
    • 1023 effect payloads hit an assert! panic (crates/plotnik-bytecode/src/bytecode/effects.rs:64) after check passed.

Approach

  • Implement Module::validate() called from from_storage: section bounds, sentinels, the already-written CRC32, the already-documented TypeDef checks. Loading invalid bytes returns ModuleError and never panics later.
  • Replace as u8 / as u16 narrowing in the emitter with try_from → a new EmitError. Draw the boundary at emit(): anything reachable from a check-clean query returns EmitError instead of panicking.
  • Move instruction encoding next to decoding in plotnik-bytecode and add roundtrip property tests (encode → decode → identical).
  • Delete the verbatim-duplicated NodeTypeIR in crates/plotnik-compiler/src/bytecode/ir.rs (the bytecode crate owns the type).

Acceptance

  • Fuzz-ish test: truncations and random corruptions of a valid module all return ModuleError on load.
  • The three capacity cases above produce compile/emit errors, not wraps or panics.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions