solana-labs / rbpf

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

Call instruction transfers control to incorrect address #539

Closed dmakarov closed 11 months ago

dmakarov commented 11 months ago

Attached a sample program that is executed incorrectly by the VM. The third instruction from the entrypoint is a call which should transfer control to instruction 270817. Instead the VM jumps to instruction 834 according to instruction trace.

sample.zip

Lichtso commented 11 months ago

It does not jump to instruction 834, but rather from that instruction. The target IP/PC is in the next line.

0 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200001000] 230885: lddw r1, 0x1001c2f38
1 [0000000000000000, 00000001001C2F38, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200001000] 230887: call function_805
2 [0000000000000000, 00000001001C2F38, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200003000]    834: callx r1
3 [0000000000000000, 00000001001C2F38, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200005000] 230880: lddw r1, 0x1002e2210

Text section vaddr: 0x100000120 Jump from: 0x100001928 Jump target: 0x1001C2F38 (0x1001C2F38 - 0x100000120) / 8 = 230851 (displayed as 230880)

Looks fine to me. You might be wondering why we still offset addresses before we display them. That is completely outdated (see https://github.com/solana-labs/rbpf/blame/main/src/ebpf.rs#L42) and we can probably remove it.

dmakarov commented 11 months ago

For this .so file I have the following disassembly

00000000001c2f38 <coretests::main>:
  230887:   18 01 00 00 10 22 2e 00 00 00 00 00 00 00 00 00 r1 = 0x2e2210 ll
  230889:   b7 02 00 00 f8 05 00 00 r2 = 0x5f8
  230890:   85 10 00 00 f6 9b 00 00 call 0x9bf6

call 0x9bf6 should jump to instruction 270817 which is test::test_main_static

 0000000000210f08 <test::test_main_static>:
  270817:   bf 14 00 00 00 00 00 00 r4 = r1

How does it end up on 834?

Lichtso commented 11 months ago

The offsets are wrong, your disassembler and the one of RBPF are not aligned. They are shifted by text_section.vaddr and ELF_INSN_DUMP_OFFSET.

dmakarov commented 11 months ago

i believe llvm-objdump offsets are correct and less concerned about offset shift. With coretests::main being the entrypoint I don’t see where and how rbpf takes the sequence of insns that it executes