Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Add a kfunc to type cast from bpf uapi ctx to kernel ctx

Implement bpf_cast_to_kern_ctx() kfunc which does a type cast
of a uapi ctx object to the corresponding kernel ctx. Previously
if users want to access some data available in kctx but not
in uapi ctx, bpf_probe_read_kernel() helper is needed.
The introduction of bpf_cast_to_kern_ctx() allows direct
memory access which makes code simpler and easier to understand.

Signed-off-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221120195432.3113982-1-yhs@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Yonghong Song and committed by
Alexei Starovoitov
fd264ca0 cfe14564

+53
+5
include/linux/btf.h
··· 487 487 btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 488 488 const struct btf_type *t, enum bpf_prog_type prog_type, 489 489 int arg); 490 + int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type); 490 491 bool btf_types_are_same(const struct btf *btf1, u32 id1, 491 492 const struct btf *btf2, u32 id2); 492 493 #else ··· 531 530 int arg) 532 531 { 533 532 return NULL; 533 + } 534 + static inline int get_kern_ctx_btf_id(struct bpf_verifier_log *log, 535 + enum bpf_prog_type prog_type) { 536 + return -EINVAL; 534 537 } 535 538 static inline bool btf_types_are_same(const struct btf *btf1, u32 id1, 536 539 const struct btf *btf2, u32 id2)
+20
kernel/bpf/btf.c
··· 5603 5603 return kern_ctx_type->type; 5604 5604 } 5605 5605 5606 + int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type) 5607 + { 5608 + const struct btf_member *kctx_member; 5609 + const struct btf_type *conv_struct; 5610 + const struct btf_type *kctx_type; 5611 + u32 kctx_type_id; 5612 + 5613 + conv_struct = bpf_ctx_convert.t; 5614 + /* get member for kernel ctx type */ 5615 + kctx_member = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2 + 1; 5616 + kctx_type_id = kctx_member->type; 5617 + kctx_type = btf_type_by_id(btf_vmlinux, kctx_type_id); 5618 + if (!btf_type_is_struct(kctx_type)) { 5619 + bpf_log(log, "kern ctx type id %u is not a struct\n", kctx_type_id); 5620 + return -EINVAL; 5621 + } 5622 + 5623 + return kctx_type_id; 5624 + } 5625 + 5606 5626 BTF_ID_LIST(bpf_ctx_convert_btf_id) 5607 5627 BTF_ID(struct, bpf_ctx_convert) 5608 5628
+6
kernel/bpf/helpers.c
··· 1879 1879 put_task_struct_rcu_user(p); 1880 1880 } 1881 1881 1882 + void *bpf_cast_to_kern_ctx(void *obj) 1883 + { 1884 + return obj; 1885 + } 1886 + 1882 1887 __diag_pop(); 1883 1888 1884 1889 BTF_SET8_START(generic_btf_ids) ··· 1912 1907 BTF_ID(func, bpf_task_release) 1913 1908 1914 1909 BTF_SET8_START(common_btf_ids) 1910 + BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx) 1915 1911 BTF_SET8_END(common_btf_ids) 1916 1912 1917 1913 static const struct btf_kfunc_id_set common_kfunc_set = {
+22
kernel/bpf/verifier.c
··· 7907 7907 u32 ref_obj_id; 7908 7908 u8 release_regno; 7909 7909 bool r0_rdonly; 7910 + u32 ret_btf_id; 7910 7911 u64 r0_size; 7911 7912 struct { 7912 7913 u64 value; ··· 8152 8151 KF_bpf_list_push_back, 8153 8152 KF_bpf_list_pop_front, 8154 8153 KF_bpf_list_pop_back, 8154 + KF_bpf_cast_to_kern_ctx, 8155 8155 }; 8156 8156 8157 8157 BTF_SET_START(special_kfunc_set) ··· 8162 8160 BTF_ID(func, bpf_list_push_back) 8163 8161 BTF_ID(func, bpf_list_pop_front) 8164 8162 BTF_ID(func, bpf_list_pop_back) 8163 + BTF_ID(func, bpf_cast_to_kern_ctx) 8165 8164 BTF_SET_END(special_kfunc_set) 8166 8165 8167 8166 BTF_ID_LIST(special_kfunc_list) ··· 8172 8169 BTF_ID(func, bpf_list_push_back) 8173 8170 BTF_ID(func, bpf_list_pop_front) 8174 8171 BTF_ID(func, bpf_list_pop_back) 8172 + BTF_ID(func, bpf_cast_to_kern_ctx) 8175 8173 8176 8174 static enum kfunc_ptr_arg_type 8177 8175 get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, ··· 8185 8181 struct bpf_reg_state *regs = cur_regs(env); 8186 8182 struct bpf_reg_state *reg = &regs[regno]; 8187 8183 bool arg_mem_size = false; 8184 + 8185 + if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) 8186 + return KF_ARG_PTR_TO_CTX; 8188 8187 8189 8188 /* In this function, we verify the kfunc's BTF as per the argument type, 8190 8189 * leaving the rest of the verification with respect to the register ··· 8675 8668 verbose(env, "arg#%d expected pointer to ctx, but got %s\n", i, btf_type_str(t)); 8676 8669 return -EINVAL; 8677 8670 } 8671 + 8672 + if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 8673 + ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog)); 8674 + if (ret < 0) 8675 + return -EINVAL; 8676 + meta->ret_btf_id = ret; 8677 + } 8678 8678 break; 8679 8679 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 8680 8680 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { ··· 8936 8922 regs[BPF_REG_0].btf = field->list_head.btf; 8937 8923 regs[BPF_REG_0].btf_id = field->list_head.value_btf_id; 8938 8924 regs[BPF_REG_0].off = field->list_head.node_offset; 8925 + } else if (meta.func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 8926 + mark_reg_known_zero(env, regs, BPF_REG_0); 8927 + regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED; 8928 + regs[BPF_REG_0].btf = desc_btf; 8929 + regs[BPF_REG_0].btf_id = meta.ret_btf_id; 8939 8930 } else { 8940 8931 verbose(env, "kernel function %s unhandled dynamic return type\n", 8941 8932 meta.func_name); ··· 15194 15175 insn_buf[1] = addr[1]; 15195 15176 insn_buf[2] = *insn; 15196 15177 *cnt = 3; 15178 + } else if (desc->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 15179 + insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1); 15180 + *cnt = 1; 15197 15181 } 15198 15182 return 0; 15199 15183 }