History

bpf: Extend kfunc with PTR_TO_CTX, PTR_TO_MEM argument support

Allow passing PTR_TO_CTX, if the kfunc expects a matching struct type, and punt to PTR_TO_MEM block if reg->type does not fall in one of PTR_TO_BTF_ID or PTR_TO_SOCK* types. This will be used by future commits to get access to XDP and TC PTR_TO_CTX, and pass various data (flags, l4proto, netns_id, etc.) encoded in opts struct passed as pointer to kfunc. For PTR_TO_MEM support, arguments are currently limited to pointer to scalar, or pointer to struct composed of scalars. This is done so that unsafe scenarios (like passing PTR_TO_MEM where PTR_TO_BTF_ID of in-kernel valid structure is expected, which may have pointers) are avoided. Since the argument checking happens basd on argument register type, it is not easy to ascertain what the expected type is. In the future, support for PTR_TO_MEM for kfunc can be extended to serve other usecases. The struct type whose pointer is passed in may have maximum nesting depth of 4, all recursively composed of scalars or struct with scalars. Future commits will add negative tests that check whether these restrictions imposed for kfunc arguments are duly rejected by BPF verifier or not.

Kumar Kartikeya Dwivedi committed 4 years ago

Commit 3363bd01 parent 7f16d2a1 file · +73 −21Browse files

Unified · Split

kernel/bpf/btf.c+73−21
@@ -5576,12 +5576,53 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = { · 5575 unmodified lines
5576#endif5576#endif
5577};5577};
5578 5578
5579/* Returns true if struct is composed of scalars, 4 levels of nesting allowed */
5580static bool __btf_type_is_scalar_struct(struct bpf_verifier_log *log,
5581 const struct btf *btf,
5582 const struct btf_type *t, int rec)
5583{
5584 const struct btf_type *member_type;
5585 const struct btf_member *member;
5586 u32 i;
5587
5588 if (!btf_type_is_struct(t))
5589 return false;
5590
5591 for_each_member(i, t, member) {
5592 const struct btf_array *array;
5593
5594 member_type = btf_type_skip_modifiers(btf, member->type, NULL);
5595 if (btf_type_is_struct(member_type)) {
5596 if (rec >= 3) {
5597 bpf_log(log, "max struct nesting depth exceeded\n");
5598 return false;
5599 }
5600 if (!__btf_type_is_scalar_struct(log, btf, member_type, rec + 1))
5601 return false;
5602 continue;
5603 }
5604 if (btf_type_is_array(member_type)) {
5605 array = btf_type_array(member_type);
5606 if (!array->nelems)
5607 return false;
5608 member_type = btf_type_skip_modifiers(btf, array->type, NULL);
5609 if (!btf_type_is_scalar(member_type))
5610 return false;
5611 continue;
5612 }
5613 if (!btf_type_is_scalar(member_type))
5614 return false;
5615 }
5616 return true;
5617}
5618
5579static int btf_check_func_arg_match(struct bpf_verifier_env *env,5619static int btf_check_func_arg_match(struct bpf_verifier_env *env,
5580 const struct btf *btf, u32 func_id,5620 const struct btf *btf, u32 func_id,
5581 struct bpf_reg_state *regs,5621 struct bpf_reg_state *regs,
5582 bool ptr_to_mem_ok)5622 bool ptr_to_mem_ok)
5583{5623{
5584 struct bpf_verifier_log *log = &env->log;5624 struct bpf_verifier_log *log = &env->log;
5625 bool is_kfunc = btf_is_kernel(btf);
5585 const char *func_name, *ref_tname;5626 const char *func_name, *ref_tname;
5586 const struct btf_type *t, *ref_t;5627 const struct btf_type *t, *ref_t;
5587 const struct btf_param *args;5628 const struct btf_param *args;
@@ -5634,7 +5675,20 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 46 unmodified lines
5634 5675
5635 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);5676 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
5636 ref_tname = btf_name_by_offset(btf, ref_t->name_off);5677 ref_tname = btf_name_by_offset(btf, ref_t->name_off);
5637 if (btf_is_kernel(btf)) {5678 if (btf_get_prog_ctx_type(log, btf, t,
5679 env->prog->type, i)) {
5680 /* If function expects ctx type in BTF check that caller
5681 * is passing PTR_TO_CTX.
5682 */
5683 if (reg->type != PTR_TO_CTX) {
5684 bpf_log(log,
5685 "arg#%d expected pointer to ctx, but got %s\n",
5686 i, btf_type_str(t));
5687 return -EINVAL;
5688 }
5689 if (check_ctx_reg(env, reg, regno))
5690 return -EINVAL;
5691 } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID || reg2btf_ids[reg->type])) {
5638 const struct btf_type *reg_ref_t;5692 const struct btf_type *reg_ref_t;
5639 const struct btf *reg_btf;5693 const struct btf *reg_btf;
5640 const char *reg_ref_tname;5694 const char *reg_ref_tname;
@@ -5650,14 +5704,9 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 9 unmodified lines
5650 if (reg->type == PTR_TO_BTF_ID) {5704 if (reg->type == PTR_TO_BTF_ID) {
5651 reg_btf = reg->btf;5705 reg_btf = reg->btf;
5652 reg_ref_id = reg->btf_id;5706 reg_ref_id = reg->btf_id;
5653 } else if (reg2btf_ids[reg->type]) {5707 } else {
5654 reg_btf = btf_vmlinux;5708 reg_btf = btf_vmlinux;
5655 reg_ref_id = *reg2btf_ids[reg->type];5709 reg_ref_id = *reg2btf_ids[reg->type];
5656 } else {
5657 bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d is not a pointer to btf_id\n",
5658 func_name, i,
5659 btf_type_str(ref_t), ref_tname, regno);
5660 return -EINVAL;
5661 }5710 }
5662 5711
5663 reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id,5712 reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id,
@@ -5673,23 +5722,24 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 9 unmodified lines
5673 reg_ref_tname);5722 reg_ref_tname);
5674 return -EINVAL;5723 return -EINVAL;
5675 }5724 }
5676 } else if (btf_get_prog_ctx_type(log, btf, t,
5677 env->prog->type, i)) {
5678 /* If function expects ctx type in BTF check that caller
5679 * is passing PTR_TO_CTX.
5680 */
5681 if (reg->type != PTR_TO_CTX) {
5682 bpf_log(log,
5683 "arg#%d expected pointer to ctx, but got %s\n",
5684 i, btf_type_str(t));
5685 return -EINVAL;
5686 }
5687 if (check_ctx_reg(env, reg, regno))
5688 return -EINVAL;
5689 } else if (ptr_to_mem_ok) {5725 } else if (ptr_to_mem_ok) {
5690 const struct btf_type *resolve_ret;5726 const struct btf_type *resolve_ret;
5691 u32 type_size;5727 u32 type_size;
5692 5728
5729 if (is_kfunc) {
5730 /* Permit pointer to mem, but only when argument
5731 * type is pointer to scalar, or struct composed
5732 * (recursively) of scalars.
5733 */
5734 if (!btf_type_is_scalar(ref_t) &&
5735 !__btf_type_is_scalar_struct(log, btf, ref_t, 0)) {
5736 bpf_log(log,
5737 "arg#%d pointer type %s %s must point to scalar or struct with scalar\n",
5738 i, btf_type_str(ref_t), ref_tname);
5739 return -EINVAL;
5740 }
5741 }
5742
5693 resolve_ret = btf_resolve_size(btf, ref_t, &type_size);5743 resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
5694 if (IS_ERR(resolve_ret)) {5744 if (IS_ERR(resolve_ret)) {
5695 bpf_log(log,5745 bpf_log(log,
@@ -5702,6 +5752,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 6 unmodified lines
5702 if (check_mem_reg(env, reg, regno, type_size))5752 if (check_mem_reg(env, reg, regno, type_size))
5703 return -EINVAL;5753 return -EINVAL;
5704 } else {5754 } else {
5755 bpf_log(log, "reg type unsupported for arg#%d %sfunction %s#%d\n", i,
5756 is_kfunc ? "kernel " : "", func_name, func_id);
5705 return -EINVAL;5757 return -EINVAL;
5706 }5758 }
5707 }5759 }
@@ -5751,7 +5803,7 @@ int btf_check_kfunc_arg_match(struct bpf_verifier_env *env, · 43 unmodified lines
5751 const struct btf *btf, u32 func_id,5803 const struct btf *btf, u32 func_id,
5752 struct bpf_reg_state *regs)5804 struct bpf_reg_state *regs)
5753{5805{
5754 return btf_check_func_arg_match(env, btf, func_id, regs, false);5806 return btf_check_func_arg_match(env, btf, func_id, regs, true);
5755}5807}
5756 5808
5757/* Convert BTF of a function into bpf_reg_state if possible5809/* Convert BTF of a function into bpf_reg_state if possible