diff options
| author | Paul Chaignon <paul.chaignon@gmail.com> | 2023-11-06 10:10:20 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2023-11-06 18:08:10 +0000 |
| commit | b1547b1e6ffceaa58562db48077ea5588372eacd (patch) | |
| tree | 4aaa54ee299e3803e57e1de0f13a26e70cdb6e00 /sys | |
| parent | 46390d8e7dd2127b50fab99fee4467aca46ab28c (diff) | |
sys/linux: describe call to bpf_tail_call helper
The bpf_tail_call helper has the following prototype.
bpf_tail_call(void *ctx, struct bpf_map *prog_array_map, u32 index)
R2 should therefore hold a pointer to a tail call map (aka, prog array
map). That tail call map should be updated such that index points to
another BPF program. In our case, index is hardcoded to 0.
Finally, R1 should hold a pointer to the context. That is always true at
the start of BPF programs so we don't change R1. If syzkaller generates
other BPF instructions between the start of the program and the
bpf_tail_call helper call, they might clobber the R1 register. That
seems unlikely to happen in practice and it's also hard to prevent it
anyway.
To load the map fd into R2, we need to templatize bpf_insn_map_fd such
that we can use it with a specific register and map fd.
There's one special case here: we need to explicitly set R0 to 0 after
the helper call because this helper has the following verifier
prototype:
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_ANYTHING,
Given the return verifier type is RET_VOID, if R0 isn't set explicitly,
the verifier will complain with "R0 !read_ok" when we exit.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/linux/bpf.txt | 21 | ||||
| -rw-r--r-- | sys/linux/bpf.txt.const | 1 |
2 files changed, 19 insertions, 3 deletions
diff --git a/sys/linux/bpf.txt b/sys/linux/bpf.txt index 539b00e3b..bfb62a629 100644 --- a/sys/linux/bpf.txt +++ b/sys/linux/bpf.txt @@ -410,6 +410,7 @@ bpf_insn [ cb_func bpf_insn_cb_func printk bpf_insn_trace_printk snprintf bpf_insn_snprintf + tail_call bpf_insn_tail_call ] [varlen] bpf_insn_generic { @@ -575,18 +576,21 @@ type bpf_insn_mov_imm64[DST, IMM1, IMM2] { imm2 const[IMM2, int32] } -bpf_insn_map_fd { +type bpf_insn_map_fd_t[DST, MAP_FD] { code const[bpf_insn_load_imm_dw, int8] - dst flags[bpf_reg, int8:4] + dst DST src const[BPF_PSEUDO_MAP_FD, int8:4] off const[0, int16] - imm fd_bpf_map + imm MAP_FD code2 const[0, int8] regs2 const[0, int8] off2 const[0, int16] imm2 const[0, int32] } +type bpf_insn_map_fd bpf_insn_map_fd_t[flags[bpf_reg, int8:4], fd_bpf_map] +type bpf_insn_tail_call_map_fd[DST] bpf_insn_map_fd_t[const[DST, int8:4], tail_call_map] + bpf_insn_map_idx { code const[bpf_insn_load_imm_dw, int8] dst flags[bpf_reg, int8:4] @@ -709,6 +713,17 @@ bpf_insn_snprintf { insn12 bpf_insn_call_helper_t[const[BPF_FUNC_snprintf, int32]] } +# (18) r2 = map[id:10] +# (b7) r3 = 2 +# (85) call bpf_tail_call#12 +# (b7) r0 = 0 +bpf_insn_tail_call { + insn1 bpf_insn_tail_call_map_fd[BPF_REG_2] + insn2 bpf_insn_mov_imm[BPF_REG_3, 0] + insn3 bpf_insn_call_helper_t[const[BPF_FUNC_tail_call, int32]] + insn4 bpf_insn_mov_imm[BPF_REG_0, 0] +} + define MAX_BPF_REG __MAX_BPF_REG bpf_obj_pin_map [ diff --git a/sys/linux/bpf.txt.const b/sys/linux/bpf.txt.const index e1d7a549e..4e55324c0 100644 --- a/sys/linux/bpf.txt.const +++ b/sys/linux/bpf.txt.const @@ -67,6 +67,7 @@ BPF_EXIT0 = 9 BPF_FLOW_DISSECTOR = 17 BPF_FUNC_INFO_SIZE = 8 BPF_FUNC_snprintf = 165 +BPF_FUNC_tail_call = 12 BPF_FUNC_trace_printk = 6 BPF_F_AFTER = 16 BPF_F_ALLOW_MULTI = 2 |
