ebpf-verifier icon indicating copy to clipboard operation
ebpf-verifier copied to clipboard

Unsupported BPF_JMP32 opcode causes failure of unmarshal in verifier

Open pcy190 opened this issue 2 years ago • 2 comments

The current ebpf-verifier doesn't appear to support BPF_JMP32_REG/BPF_JMP32_IMMinstruction parsing.

When we construct the BPF_JMP32_REG instruction, as is defined in bpf-instruction.h of Linux kernel:

#define BPF_JMP32_REG(OP, DST, SRC, OFF)            \
    ((struct bpf_insn) {                    \
        .code  = BPF_JMP32 | BPF_OP(OP) | BPF_X,    \
        .dst_reg = DST,                    \
        .src_reg = SRC,                    \
        .off   = OFF,                    \
        .imm   = 0 })

The opcode should be BPF_JMP32 | BPF_OP(OP) | BPF_X.

Considering that the OP is BPF_JLT as 0xa0 which defined in https://github.com/torvalds/linux/blob/50be9417e23af5a8ac860d998e1e3f06b8fd79d7/include/uapi/linux/bpf.h#L38

The BPF_JMP32 macro is 0x6 which defined in https://github.com/torvalds/linux/blob/50be9417e23af5a8ac860d998e1e3f06b8fd79d7/include/uapi/linux/bpf.h#L17

And BPF_X macro is 0x08 which defined in https://github.com/torvalds/linux/blob/50be9417e23af5a8ac860d998e1e3f06b8fd79d7/include/uapi/linux/bpf_common.h#L51

The BPF_OP is defined in https://github.com/torvalds/linux/blob/50be9417e23af5a8ac860d998e1e3f06b8fd79d7/include/uapi/linux/bpf_common.h#L31

#define BPF_OP(code)    ((code) & 0xf0)

Hence the opcode is

0x6 |  (0xa0 & 0xf0) | 0x6 = 0xa6

When the instruction opcode firstly parsed in unmarshal function, it will fetch this 0xa6 & INST_CLS_MASK opcode as 0x6 and fall into the INST_CLS_UNUSED cases which throws invalid class 0x6 exception. https://github.com/vbpf/ebpf-verifier/blob/cc3108a4c6c1c6c3a5ba38dd46cfee1c8fed4560/src/asm_unmarshal.cpp#L373-L402

Hence if we pass the below example BPF_JMP32_IMM instruction bytecode to the verifier, it fails with unmarshaling error at 19: invalid class 0x6 exception.

// if w5 < 0x7fffffff goto pc+1
a6 05 01 00 ff ff ff 7f 13 

Wondering whether the lack of support for BPF_JMP32 is expected in the design of the ebpf-verifier, while the Linux kernel verifier supports it.

Thanks.

pcy190 avatar Jul 10 '21 13:07 pcy190

Wondering whether it is necessary to support BPF_JMP32? @dthaler

Perhaps we need to add 32bit cases for makeJmp function.

pcy190 avatar Aug 25 '21 14:08 pcy190

As @Alan-Jowett noted in #276, the workaround appears to be to compile the program with --target=bpf -mcpu=v1 so that clang doesn't emit the newer instruction types. That said, I suspect it's not that difficult to add support for, but given the workaround it's probably lower priority than other issues.

dthaler avatar Oct 06 '21 22:10 dthaler