solana-labs / rbpf

Rust virtual machine and JIT compiler for eBPF programs
Apache License 2.0
277 stars 169 forks source link

Attempt to negate with overflow in disassembler #549

Closed pcy190 closed 10 months ago

pcy190 commented 10 months ago

When overflow-check is enabled, the disassembler would panic in signed_off_str when it tries to negate the 0x8000i16 value in https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/disassembler.rs#L46-L52

The text bytes PoC to trigger it:

[0x7b, 0x21, 0x00, 0x80, 0, 0, 0, 0]

The test code to reproduce:

let loader = BuiltinProgram::new_loader(
        Config::default(),
        FunctionRegistry::default(),
    );
let mut executable = Executable::<TestContextObject>::from_text_bytes(
    &[0x7b, 0x21, 0x00, 0x80, 0, 0, 0, 0],
    std::sync::Arc::new(loader),
    solana_rbpf::program::SBPFVersion::V2,
    FunctionRegistry::default(),
).unwrap();
let analysis = Analysis::from_executable(&executable).unwrap();
let mut reasm = Vec::new();
analysis.disassemble(&mut reasm).unwrap();

Running it in debug mode would encounter:

attempt to negate with overflow
thread 'test_store_negate' panicked at 'attempt to negate with overflow', src/disassembler.rs:48:27
stack backtrace:
   0: rust_begin_unwind
             at /rustc/*/library/std/src/panicking.rs:593:5
   1: core::panicking::panic_fmt
             at /rustc/*/library/core/src/panicking.rs:67:14
   2: core::panicking::panic
             at /rustc/*/library/core/src/panicking.rs:117:5
   3: solana_rbpf::disassembler::signed_off_str
             at ./src/disassembler.rs:48:27
   4: solana_rbpf::disassembler::st_reg_str
             at ./src/disassembler.rs:82:9
   5: solana_rbpf::disassembler::disassemble_instruction
             at ./src/disassembler.rs:142:58

In release mode, the disassembler result would be stxdw [r1-0x8000], r2, which doesn't necessarily pose the wrong result.

However, to enhance the robustness of the disassembler, the negate logic of i16 could be restructured in signed_off_str function.