diff options
| author | Paul Chaignon <paul.chaignon@gmail.com> | 2023-10-02 13:19:01 +0200 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2023-10-16 15:57:22 +0000 |
| commit | 8ad4a8143de26cbdb7d7b9e4e4477eab73a146ff (patch) | |
| tree | 42822ab9a00c7488ace6ff5bbdd8e6babcb23d5c /sys | |
| parent | 93789af44b9ab48817ad60d9e8657bc46eea6202 (diff) | |
sys/linux: describe full call to bpf_snprintf helper
This commit describes the full snippet of BPF bytecode required to
successfully call the bpf_snprintf helper.
That helper has the following prototype:
long bpf_snprintf(char *str, u32 str_size, const char *fmt, u64 *data, u32 data_len)
with the following verifier types:
.arg1_type = ARG_PTR_TO_MEM_OR_NULL,
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
.arg3_type = ARG_PTR_TO_CONST_STR,
.arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
The first and fourth arguments can point to nulled buffers on the stack.
The second and fifth arguments contain the sizes of those buffers.
Finally, the third argument must point to a map holding a constant
string; we can use the type introduced in the previous commit for that.
The corresponding eBPF bytecode is kept in comment as that is much
easier to parse for anyone familiar with the bytecode.
In addition to the test case introduced in the next commit, this
description was tested by running syzkaller with a focus on the
necessary bpf syscalls. Specifically, syscalls bpf$MAP_CREATE_CONST_STR,
bpf$MAP_UPDATE_CONST_STR, bpf$BPF_MAP_CONST_STR_FREEZE, bpf$PROG_LOAD,
and bpf$BPF_PROG_TEST_RUN were executed on 16 VMs (with two logical
cores each). Syzkaller was then able to reach the formatter parsing
logic of function bpf_bprintf_prepare [1], which bpf_snprintf calls.
1 - https://github.com/torvalds/linux/blob/v6.5/kernel/bpf/helpers.c#L875
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/linux/bpf.txt | 29 | ||||
| -rw-r--r-- | sys/linux/bpf.txt.const | 1 |
2 files changed, 30 insertions, 0 deletions
diff --git a/sys/linux/bpf.txt b/sys/linux/bpf.txt index b50f49ef2..f4b018ada 100644 --- a/sys/linux/bpf.txt +++ b/sys/linux/bpf.txt @@ -386,6 +386,7 @@ bpf_insn [ btf_id bpf_insn_btf_id cb_func bpf_insn_cb_func printk bpf_insn_trace_printk + snprintf bpf_insn_snprintf ] [varlen] bpf_insn_generic { @@ -587,6 +588,7 @@ type bpf_insn_map_value_t[DST, MAP_FD, VALUE_OFFSET] { } type bpf_insn_map_value bpf_insn_map_value_t[flags[bpf_reg, int8:4], fd_bpf_map, int32] +type bpf_insn_const_str[DST] bpf_insn_map_value_t[const[DST, int8:4], bpf_frozen_const_str, const[0, int32]] bpf_insn_map_idx_value { code const[bpf_insn_load_imm_dw, int8] @@ -656,6 +658,33 @@ bpf_insn_trace_printk { insn7 bpf_insn_call_helper_t[const[BPF_FUNC_trace_printk, int32]] } +# (b7) r8 = 0 +# (7b) *(u64 *)(r10 -8) = r8 +# (b7) r8 = X +# (7b) *(u64 *)(r10 -16) = r8 +# (bf) r1 = r10 +# (07) r1 += -8 +# (bf) r4 = r10 +# (07) r4 += -16 +# (b7) r2 = 8 +# (18) r3 = map[id:31][0]+0 +# (b7) r5 = 8 +# (85) call bpf_snprintf#168880 +bpf_insn_snprintf { + insn1 bpf_insn_mov_imm[BPF_REG_8, 0] + insn2 bpf_insn_st64_reg[BPF_REG_8, BPF_REG_10, -8] + insn3 bpf_insn_mov_imm_any[BPF_REG_8] + insn4 bpf_insn_st64_reg[BPF_REG_8, BPF_REG_10, -16] + insn5 bpf_insn_mov_reg[BPF_REG_10, BPF_REG_1] + insn6 bpf_insn_op_imm[BPF_REG_1, BPF_ADD0, -8] + insn7 bpf_insn_mov_reg[BPF_REG_10, BPF_REG_4] + insn8 bpf_insn_op_imm[BPF_REG_4, BPF_ADD0, -16] + insn9 bpf_insn_mov_imm[BPF_REG_2, 8] + insn10 bpf_insn_const_str[BPF_REG_3] + insn11 bpf_insn_mov_imm[BPF_REG_5, 8] + insn12 bpf_insn_call_helper_t[const[BPF_FUNC_snprintf, int32]] +} + 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 e6eff547d..07c73dece 100644 --- a/sys/linux/bpf.txt.const +++ b/sys/linux/bpf.txt.const @@ -61,6 +61,7 @@ BPF_EXIST = 2 BPF_EXIT0 = 9 BPF_FLOW_DISSECTOR = 17 BPF_FUNC_INFO_SIZE = 8 +BPF_FUNC_snprintf = 165 BPF_FUNC_trace_printk = 6 BPF_F_AFTER = 16 BPF_F_ALLOW_MULTI = 2 |
