qmonnet / rbpf

Rust virtual machine and JIT compiler for eBPF programs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Attempt to calculate the remainder with a divisor of zero for MOD32 in interpreter

pcy190 opened this issue · comments

Details

In the implementation of MOD32, it checks whether the 64-bit source value is zero. However, during the modulus computation, the source is casted to 32-bit, which could still be zero, e.g., 0xffff0000. According to the kernel ebpf standard, we should check the modulo by zero by checking the nullness of the 32-bit source value.

https://github.com/torvalds/linux/blob/610a9b8f49fbcf1100716370d3b5f6f884a2835a/Documentation/bpf/standardization/instruction-set.rst?plain=1#L246-L251

If execution would result in modulo by zero, for BPF_ALU64 the value of
the destination register is unchanged whereas for BPF_ALU the upper
32 bits of the destination register are zeroed.

The current implementation of MOD32_IMM and MOD32_REG lacks the check to the lower 32 bits of source value.

rbpf/src/interpreter.rs

Lines 230 to 233 in 4812c52

ebpf::MOD32_IMM if insn.imm == 0 => (),
ebpf::MOD32_IMM => reg[_dst] = (reg[_dst] as u32 % insn.imm as u32) as u64,
ebpf::MOD32_REG if reg[_src] == 0 => (),
ebpf::MOD32_REG => reg[_dst] = (reg[_dst] as u32 % reg[_src] as u32) as u64,

The following PoC program would cause the attempt to calculate the remainder with a divisor of zero panic in the interpreter:

lddw r1, 0x100000000
mod32 r0, r1
exit

Result:

attempt to calculate the remainder with a divisor of zero
thread '' panicked at 'attempt to calculate the remainder with a divisor of zero', src/interpreter.rs:235:47
stack backtrace:
...
   3: rbpf::interpreter::execute_program
             at ./src/interpreter.rs:235:47
   4: rbpf::EbpfVmMbuff::execute_program
             at ./src/lib.rs:300:9
   5: rbpf::EbpfVmRaw::execute_program
             at ./src/lib.rs:1221:9
   6: rbpf::EbpfVmNoData::execute_program
             at ./src/lib.rs:1581:9

Suggestion

Check nullness of 32-bit casted source value before modulus

Good catch, thank you!