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

bpf/verifier: allow kfunc to return an allocated mem

For drivers (outside of network), the incoming data is not statically
defined in a struct. Most of the time the data buffer is kzalloc-ed
and thus we can not rely on eBPF and BTF to explore the data.

This commit allows to return an arbitrary memory, previously allocated by
the driver.
An interesting extra point is that the kfunc can mark the exported
memory region as read only or read/write.

So, when a kfunc is not returning a pointer to a struct but to a plain
type, we can consider it is a valid allocated memory assuming that:
- one of the arguments is either called rdonly_buf_size or
rdwr_buf_size
- and this argument is a const from the caller point of view

We can then use this parameter as the size of the allocated memory.

The memory is either read-only or read-write based on the name
of the size parameter.

Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Link: https://lore.kernel.org/r/20220906151303.2780789-7-benjamin.tissoires@redhat.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Benjamin Tissoires and committed by
Alexei Starovoitov
eb1f7f71 f9b34818

+133 -34
+8 -1
include/linux/bpf.h
··· 1944 1944 const char *func_name, 1945 1945 struct btf_func_model *m); 1946 1946 1947 + struct bpf_kfunc_arg_meta { 1948 + u64 r0_size; 1949 + bool r0_rdonly; 1950 + int ref_obj_id; 1951 + u32 flags; 1952 + }; 1953 + 1947 1954 struct bpf_reg_state; 1948 1955 int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog, 1949 1956 struct bpf_reg_state *regs); ··· 1959 1952 int btf_check_kfunc_arg_match(struct bpf_verifier_env *env, 1960 1953 const struct btf *btf, u32 func_id, 1961 1954 struct bpf_reg_state *regs, 1962 - u32 kfunc_flags); 1955 + struct bpf_kfunc_arg_meta *meta); 1963 1956 int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog, 1964 1957 struct bpf_reg_state *reg); 1965 1958 int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog,
+2
include/linux/bpf_verifier.h
··· 598 598 struct bpf_attach_target_info *tgt_info); 599 599 void bpf_free_kfunc_btf_tab(struct bpf_kfunc_btf_tab *tab); 600 600 601 + int mark_chain_precision(struct bpf_verifier_env *env, int regno); 602 + 601 603 #define BPF_BASE_TYPE_MASK GENMASK(BPF_BASE_TYPE_BITS - 1, 0) 602 604 603 605 /* extract base type from bpf_{arg, return, reg}_type. */
+10
include/linux/btf.h
··· 441 441 } 442 442 #endif 443 443 444 + static inline bool btf_type_is_struct_ptr(struct btf *btf, const struct btf_type *t) 445 + { 446 + if (!btf_type_is_ptr(t)) 447 + return false; 448 + 449 + t = btf_type_skip_modifiers(btf, t->type, NULL); 450 + 451 + return btf_type_is_struct(t); 452 + } 453 + 444 454 #endif
+81 -20
kernel/bpf/btf.c
··· 6199 6199 return true; 6200 6200 } 6201 6201 6202 + static bool btf_is_kfunc_arg_mem_size(const struct btf *btf, 6203 + const struct btf_param *arg, 6204 + const struct bpf_reg_state *reg, 6205 + const char *name) 6206 + { 6207 + int len, target_len = strlen(name); 6208 + const struct btf_type *t; 6209 + const char *param_name; 6210 + 6211 + t = btf_type_skip_modifiers(btf, arg->type, NULL); 6212 + if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE) 6213 + return false; 6214 + 6215 + param_name = btf_name_by_offset(btf, arg->name_off); 6216 + if (str_is_empty(param_name)) 6217 + return false; 6218 + len = strlen(param_name); 6219 + if (len != target_len) 6220 + return false; 6221 + if (strcmp(param_name, name)) 6222 + return false; 6223 + 6224 + return true; 6225 + } 6226 + 6202 6227 static int btf_check_func_arg_match(struct bpf_verifier_env *env, 6203 6228 const struct btf *btf, u32 func_id, 6204 6229 struct bpf_reg_state *regs, 6205 6230 bool ptr_to_mem_ok, 6206 - u32 kfunc_flags, 6231 + struct bpf_kfunc_arg_meta *kfunc_meta, 6207 6232 bool processing_call) 6208 6233 { 6209 6234 enum bpf_prog_type prog_type = resolve_prog_type(env->prog); ··· 6266 6241 return -EINVAL; 6267 6242 } 6268 6243 6269 - if (is_kfunc) { 6244 + if (is_kfunc && kfunc_meta) { 6270 6245 /* Only kfunc can be release func */ 6271 - rel = kfunc_flags & KF_RELEASE; 6272 - kptr_get = kfunc_flags & KF_KPTR_GET; 6273 - trusted_arg = kfunc_flags & KF_TRUSTED_ARGS; 6274 - sleepable = kfunc_flags & KF_SLEEPABLE; 6246 + rel = kfunc_meta->flags & KF_RELEASE; 6247 + kptr_get = kfunc_meta->flags & KF_KPTR_GET; 6248 + trusted_arg = kfunc_meta->flags & KF_TRUSTED_ARGS; 6249 + sleepable = kfunc_meta->flags & KF_SLEEPABLE; 6275 6250 } 6276 6251 6277 6252 /* check that BTF function arguments match actual types that the ··· 6284 6259 6285 6260 t = btf_type_skip_modifiers(btf, args[i].type, NULL); 6286 6261 if (btf_type_is_scalar(t)) { 6262 + if (is_kfunc && kfunc_meta) { 6263 + bool is_buf_size = false; 6264 + 6265 + /* check for any const scalar parameter of name "rdonly_buf_size" 6266 + * or "rdwr_buf_size" 6267 + */ 6268 + if (btf_is_kfunc_arg_mem_size(btf, &args[i], reg, 6269 + "rdonly_buf_size")) { 6270 + kfunc_meta->r0_rdonly = true; 6271 + is_buf_size = true; 6272 + } else if (btf_is_kfunc_arg_mem_size(btf, &args[i], reg, 6273 + "rdwr_buf_size")) 6274 + is_buf_size = true; 6275 + 6276 + if (is_buf_size) { 6277 + if (kfunc_meta->r0_size) { 6278 + bpf_log(log, "2 or more rdonly/rdwr_buf_size parameters for kfunc"); 6279 + return -EINVAL; 6280 + } 6281 + 6282 + if (!tnum_is_const(reg->var_off)) { 6283 + bpf_log(log, "R%d is not a const\n", regno); 6284 + return -EINVAL; 6285 + } 6286 + 6287 + kfunc_meta->r0_size = reg->var_off.value; 6288 + ret = mark_chain_precision(env, regno); 6289 + if (ret) 6290 + return ret; 6291 + } 6292 + } 6293 + 6287 6294 if (reg->type == SCALAR_VALUE) 6288 6295 continue; 6289 6296 bpf_log(log, "R%d is not a scalar\n", regno); ··· 6345 6288 ret = check_func_arg_reg_off(env, reg, regno, arg_type); 6346 6289 if (ret < 0) 6347 6290 return ret; 6291 + 6292 + if (is_kfunc && reg->ref_obj_id) { 6293 + /* Ensure only one argument is referenced PTR_TO_BTF_ID */ 6294 + if (ref_obj_id) { 6295 + bpf_log(log, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n", 6296 + regno, reg->ref_obj_id, ref_obj_id); 6297 + return -EFAULT; 6298 + } 6299 + ref_regno = regno; 6300 + ref_obj_id = reg->ref_obj_id; 6301 + } 6348 6302 6349 6303 /* kptr_get is only true for kfunc */ 6350 6304 if (i == 0 && kptr_get) { ··· 6429 6361 if (reg->type == PTR_TO_BTF_ID) { 6430 6362 reg_btf = reg->btf; 6431 6363 reg_ref_id = reg->btf_id; 6432 - /* Ensure only one argument is referenced PTR_TO_BTF_ID */ 6433 - if (reg->ref_obj_id) { 6434 - if (ref_obj_id) { 6435 - bpf_log(log, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n", 6436 - regno, reg->ref_obj_id, ref_obj_id); 6437 - return -EFAULT; 6438 - } 6439 - ref_regno = regno; 6440 - ref_obj_id = reg->ref_obj_id; 6441 - } 6442 6364 } else { 6443 6365 reg_btf = btf_vmlinux; 6444 6366 reg_ref_id = *reg2btf_ids[base_type(reg->type)]; ··· 6519 6461 return -EINVAL; 6520 6462 } 6521 6463 6464 + if (kfunc_meta && ref_obj_id) 6465 + kfunc_meta->ref_obj_id = ref_obj_id; 6466 + 6522 6467 /* returns argument register number > 0 in case of reference release kfunc */ 6523 6468 return rel ? ref_regno : 0; 6524 6469 } ··· 6553 6492 return -EINVAL; 6554 6493 6555 6494 is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL; 6556 - err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, 0, false); 6495 + err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, NULL, false); 6557 6496 6558 6497 /* Compiler optimizations can remove arguments from static functions 6559 6498 * or mismatched type can be passed into a global function. ··· 6596 6535 return -EINVAL; 6597 6536 6598 6537 is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL; 6599 - err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, 0, true); 6538 + err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, NULL, true); 6600 6539 6601 6540 /* Compiler optimizations can remove arguments from static functions 6602 6541 * or mismatched type can be passed into a global function. ··· 6610 6549 int btf_check_kfunc_arg_match(struct bpf_verifier_env *env, 6611 6550 const struct btf *btf, u32 func_id, 6612 6551 struct bpf_reg_state *regs, 6613 - u32 kfunc_flags) 6552 + struct bpf_kfunc_arg_meta *meta) 6614 6553 { 6615 - return btf_check_func_arg_match(env, btf, func_id, regs, true, kfunc_flags, true); 6554 + return btf_check_func_arg_match(env, btf, func_id, regs, true, meta, true); 6616 6555 } 6617 6556 6618 6557 /* Convert BTF of a function into bpf_reg_state if possible
+32 -13
kernel/bpf/verifier.c
··· 2908 2908 return 0; 2909 2909 } 2910 2910 2911 - static int mark_chain_precision(struct bpf_verifier_env *env, int regno) 2911 + int mark_chain_precision(struct bpf_verifier_env *env, int regno) 2912 2912 { 2913 2913 return __mark_chain_precision(env, regno, -1); 2914 2914 } ··· 7595 7595 { 7596 7596 const struct btf_type *t, *func, *func_proto, *ptr_type; 7597 7597 struct bpf_reg_state *regs = cur_regs(env); 7598 + struct bpf_kfunc_arg_meta meta = { 0 }; 7598 7599 const char *func_name, *ptr_type_name; 7599 7600 u32 i, nargs, func_id, ptr_type_id; 7600 7601 int err, insn_idx = *insn_idx_p; ··· 7630 7629 7631 7630 acq = *kfunc_flags & KF_ACQUIRE; 7632 7631 7632 + meta.flags = *kfunc_flags; 7633 + 7633 7634 /* Check the arguments */ 7634 - err = btf_check_kfunc_arg_match(env, desc_btf, func_id, regs, *kfunc_flags); 7635 + err = btf_check_kfunc_arg_match(env, desc_btf, func_id, regs, &meta); 7635 7636 if (err < 0) 7636 7637 return err; 7637 7638 /* In case of release function, we get register number of refcounted ··· 7654 7651 /* Check return type */ 7655 7652 t = btf_type_skip_modifiers(desc_btf, func_proto->type, NULL); 7656 7653 7657 - if (acq && !btf_type_is_ptr(t)) { 7654 + if (acq && !btf_type_is_struct_ptr(desc_btf, t)) { 7658 7655 verbose(env, "acquire kernel function does not return PTR_TO_BTF_ID\n"); 7659 7656 return -EINVAL; 7660 7657 } ··· 7666 7663 ptr_type = btf_type_skip_modifiers(desc_btf, t->type, 7667 7664 &ptr_type_id); 7668 7665 if (!btf_type_is_struct(ptr_type)) { 7669 - ptr_type_name = btf_name_by_offset(desc_btf, 7670 - ptr_type->name_off); 7671 - verbose(env, "kernel function %s returns pointer type %s %s is not supported\n", 7672 - func_name, btf_type_str(ptr_type), 7673 - ptr_type_name); 7674 - return -EINVAL; 7666 + if (!meta.r0_size) { 7667 + ptr_type_name = btf_name_by_offset(desc_btf, 7668 + ptr_type->name_off); 7669 + verbose(env, 7670 + "kernel function %s returns pointer type %s %s is not supported\n", 7671 + func_name, 7672 + btf_type_str(ptr_type), 7673 + ptr_type_name); 7674 + return -EINVAL; 7675 + } 7676 + 7677 + mark_reg_known_zero(env, regs, BPF_REG_0); 7678 + regs[BPF_REG_0].type = PTR_TO_MEM; 7679 + regs[BPF_REG_0].mem_size = meta.r0_size; 7680 + 7681 + if (meta.r0_rdonly) 7682 + regs[BPF_REG_0].type |= MEM_RDONLY; 7683 + 7684 + /* Ensures we don't access the memory after a release_reference() */ 7685 + if (meta.ref_obj_id) 7686 + regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id; 7687 + } else { 7688 + mark_reg_known_zero(env, regs, BPF_REG_0); 7689 + regs[BPF_REG_0].btf = desc_btf; 7690 + regs[BPF_REG_0].type = PTR_TO_BTF_ID; 7691 + regs[BPF_REG_0].btf_id = ptr_type_id; 7675 7692 } 7676 - mark_reg_known_zero(env, regs, BPF_REG_0); 7677 - regs[BPF_REG_0].btf = desc_btf; 7678 - regs[BPF_REG_0].type = PTR_TO_BTF_ID; 7679 - regs[BPF_REG_0].btf_id = ptr_type_id; 7680 7693 if (*kfunc_flags & KF_RET_NULL) { 7681 7694 regs[BPF_REG_0].type |= PTR_MAYBE_NULL; 7682 7695 /* For mark_ptr_or_null_reg, see 93c230e3f5bd6 */