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

bpf: Add a kfunc for generic type cast

Implement bpf_rdonly_cast() which tries to cast the object
to a specified type. This tries to support use case like below:
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
where skb_end_pointer(SKB) is a 'unsigned char *' and needs to
be casted to 'struct skb_shared_info *'.

The signature of bpf_rdonly_cast() looks like
void *bpf_rdonly_cast(void *obj, __u32 btf_id)
The function returns the same 'obj' but with PTR_TO_BTF_ID with
btf_id. The verifier will ensure btf_id being a struct type.

Since the supported type cast may not reflect what the 'obj'
represents, the returned btf_id is marked as PTR_UNTRUSTED, so
the return value and subsequent pointer chasing cannot be
used as helper/kfunc arguments.

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

authored by

Yonghong Song and committed by
Alexei Starovoitov
a35b9af4 fd264ca0

+24 -2
+6
kernel/bpf/helpers.c
··· 1884 1884 return obj; 1885 1885 } 1886 1886 1887 + void *bpf_rdonly_cast(void *obj__ign, u32 btf_id__k) 1888 + { 1889 + return obj__ign; 1890 + } 1891 + 1887 1892 __diag_pop(); 1888 1893 1889 1894 BTF_SET8_START(generic_btf_ids) ··· 1918 1913 1919 1914 BTF_SET8_START(common_btf_ids) 1920 1915 BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx) 1916 + BTF_ID_FLAGS(func, bpf_rdonly_cast) 1921 1917 BTF_SET8_END(common_btf_ids) 1922 1918 1923 1919 static const struct btf_kfunc_id_set common_kfunc_set = {
+18 -2
kernel/bpf/verifier.c
··· 8153 8153 KF_bpf_list_pop_front, 8154 8154 KF_bpf_list_pop_back, 8155 8155 KF_bpf_cast_to_kern_ctx, 8156 + KF_bpf_rdonly_cast, 8156 8157 }; 8157 8158 8158 8159 BTF_SET_START(special_kfunc_set) ··· 8164 8163 BTF_ID(func, bpf_list_pop_front) 8165 8164 BTF_ID(func, bpf_list_pop_back) 8166 8165 BTF_ID(func, bpf_cast_to_kern_ctx) 8166 + BTF_ID(func, bpf_rdonly_cast) 8167 8167 BTF_SET_END(special_kfunc_set) 8168 8168 8169 8169 BTF_ID_LIST(special_kfunc_list) ··· 8175 8173 BTF_ID(func, bpf_list_pop_front) 8176 8174 BTF_ID(func, bpf_list_pop_back) 8177 8175 BTF_ID(func, bpf_cast_to_kern_ctx) 8176 + BTF_ID(func, bpf_rdonly_cast) 8178 8177 8179 8178 static enum kfunc_ptr_arg_type 8180 8179 get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, ··· 8812 8809 u32 i, nargs, func_id, ptr_type_id; 8813 8810 int err, insn_idx = *insn_idx_p; 8814 8811 const struct btf_param *args; 8812 + const struct btf_type *ret_t; 8815 8813 struct btf *desc_btf; 8816 8814 u32 *kfunc_flags; 8817 8815 ··· 8892 8888 8893 8889 if (meta.btf == btf_vmlinux && btf_id_set_contains(&special_kfunc_set, meta.func_id)) { 8894 8890 if (meta.func_id == special_kfunc_list[KF_bpf_obj_new_impl]) { 8895 - const struct btf_type *ret_t; 8896 8891 struct btf *ret_btf; 8897 8892 u32 ret_btf_id; 8898 8893 ··· 8944 8941 regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED; 8945 8942 regs[BPF_REG_0].btf = desc_btf; 8946 8943 regs[BPF_REG_0].btf_id = meta.ret_btf_id; 8944 + } else if (meta.func_id == special_kfunc_list[KF_bpf_rdonly_cast]) { 8945 + ret_t = btf_type_by_id(desc_btf, meta.arg_constant.value); 8946 + if (!ret_t || !btf_type_is_struct(ret_t)) { 8947 + verbose(env, 8948 + "kfunc bpf_rdonly_cast type ID argument must be of a struct\n"); 8949 + return -EINVAL; 8950 + } 8951 + 8952 + mark_reg_known_zero(env, regs, BPF_REG_0); 8953 + regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_UNTRUSTED; 8954 + regs[BPF_REG_0].btf = desc_btf; 8955 + regs[BPF_REG_0].btf_id = meta.arg_constant.value; 8947 8956 } else { 8948 8957 verbose(env, "kernel function %s unhandled dynamic return type\n", 8949 8958 meta.func_name); ··· 15209 15194 insn_buf[1] = addr[1]; 15210 15195 insn_buf[2] = *insn; 15211 15196 *cnt = 3; 15212 - } else if (desc->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 15197 + } else if (desc->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] || 15198 + desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) { 15213 15199 insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1); 15214 15200 *cnt = 1; 15215 15201 }