-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Description
ExtendedOpcode::MAX is computed as the variant count (N), not the max discriminant (N-1). new() checks bytes <= MAX, so new(N) passes validation and reaches transmute(N) on an invalid discriminant . Reachable via Disassembler::disassemble_all on 3 crafted bytes; Miri confirms. Niche optimisation currently masks it (Some(transmute(N)) bit-aliases None), but that's a layout coincidence.
Minimal PoC:
$ cat src/main.rs
//! `ExtendedOpcode::MAX` is the variant *count* (310), not the max
//! discriminant (309). `new()` checks `<= MAX`, so `new(310)` reaches
//! `transmute(310)` — UB. Miri catches it; natively it niche-collapses
//! to `None` by coincidence.
//!
//! cargo +nightly miri run
#![forbid(unsafe_code)]
use pulley_interpreter::disas::Disassembler;
use pulley_interpreter::opcode::{ExtendedOpcode, Opcode};
fn main() {
// Safe public disassembler → SafeBytecodeStream → ExtendedOpcode::new(MAX)
let bytes = [
Opcode::ExtendedOp as u8,
ExtendedOpcode::MAX as u8,
(ExtendedOpcode::MAX >> 8) as u8,
];
let _ = Disassembler::disassemble_all(&bytes);
}
$ cargo miri run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `/root/.rustup/toolchains/nightly-2025-12-06-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/poc_bug_029`
error: Undefined Behavior: constructing invalid value at .<enum-tag>: encountered 0x0136, but expected a valid enum tag
--> /root/home/opensrc/wasmtime/pulley/src/opcode.rs:104:18
|
104 | unsafe { core::mem::transmute(byte) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `pulley_interpreter::ExtendedOpcode::unchecked_new` at /root/home/opensrc/wasmtime/pulley/src/opcode.rs:104:18: 104:44
= note: inside `pulley_interpreter::ExtendedOpcode::new` at /root/home/opensrc/wasmtime/pulley/src/opcode.rs:91:27: 91:53
= note: inside `pulley_interpreter::decode::decode_one_extended::<pulley_interpreter::disas::Disassembler<'_>>` at /root/home/opensrc/wasmtime/pulley/src/decode.rs:707:26: 707:51
= note: inside `pulley_interpreter::decode::Decoder::decode_one::<pulley_interpreter::disas::Disassembler<'_>>` at /root/home/opensrc/wasmtime/pulley/src/decode.rs:601:25: 601:53
= note: inside `pulley_interpreter::decode::Decoder::decode_all::<'_, pulley_interpreter::disas::Disassembler<'_>>` at /root/home/opensrc/wasmtime/pulley/src/decode.rs:528:26: 528:53
= note: inside `pulley_interpreter::disas::Disassembler::<'_>::disassemble_all` at /root/home/opensrc/wasmtime/pulley/src/disas.rs:32:9: 32:40
note: inside `main`
--> src/main.rs:19:13
|
19 | let _ = Disassembler::disassemble_all(&bytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error
Not a security issue because pully is a tier 2 feature.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels