Skip to content

bytecode: reject jump targets landing inside multi-step instructions on load #457

Description

@zharinov

Module::validate_opcodes walks the transitions section one instruction at a time, advancing by each opcode's step count, and only checks the opcodes it lands on. The interior steps of a multi-step instruction (for example Match16, which spans two steps) are skipped.

A hand-crafted module can therefore pass load and then panic at runtime:

  • step 0 is Match16 (covers steps 0 and 1)
  • step 1 holds an invalid opcode nibble (0x90xF)
  • an entrypoint or a Match successor targets step 1
  • validate_opcodes jumps from step 0 to step 2 and never inspects step 1
  • the VM later decodes step 1 and hits expect("invalid opcode")

This only affects deliberately forged modules. The binary format's threat model already treats forged-checksum modules as out of scope (see the note above Module::validate in crates/plotnik-bytecode/src/bytecode/module.rs), and a normal compiler-emitted module never reaches this. So this is hardening, not a correctness bug.

Fix idea

  • Record the valid instruction-start steps while walking the transitions section.
  • Reject any entrypoint or Match successor that targets a step that is not an instruction start.
  • Reject any instruction whose step_count overshoots the end of the section.

Found during a boundaries refactor and left out of that PR on purpose, because it changes load behavior (it would reject modules that load today). Related to the closed #422.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions