aboutsummaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorPaul Chaignon <paul.chaignon@gmail.com>2023-10-02 13:19:01 +0200
committerAleksandr Nogikh <nogikh@google.com>2023-10-16 15:57:22 +0000
commit8ad4a8143de26cbdb7d7b9e4e4477eab73a146ff (patch)
tree42822ab9a00c7488ace6ff5bbdd8e6babcb23d5c /sys
parent93789af44b9ab48817ad60d9e8657bc46eea6202 (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.txt29
-rw-r--r--sys/linux/bpf.txt.const1
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