ebpf-verifier
ebpf-verifier copied to clipboard
Unsupported BPF_JMP32 opcode causes failure of unmarshal in verifier
The current ebpf-verifier doesn't appear to support BPF_JMP32_REG
/BPF_JMP32_IMM
instruction 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.
Wondering whether it is necessary to support BPF_JMP32
? @dthaler
Perhaps we need to add 32bit cases for makeJmp
function.
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.