Skip to content

Commit 3363bd0

Browse files
kkdwivediAlexei Starovoitov
authored and
Alexei Starovoitov
committed
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. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 7f16d2a commit 3363bd0

File tree

1 file changed

+73
-21
lines changed

1 file changed

+73
-21
lines changed

kernel/bpf/btf.c

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5576,12 +5576,53 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
55765576
#endif
55775577
};
55785578

5579+
/* Returns true if struct is composed of scalars, 4 levels of nesting allowed */
5580+
static 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+
55795619
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
55805620
const struct btf *btf, u32 func_id,
55815621
struct bpf_reg_state *regs,
55825622
bool ptr_to_mem_ok)
55835623
{
55845624
struct bpf_verifier_log *log = &env->log;
5625+
bool is_kfunc = btf_is_kernel(btf);
55855626
const char *func_name, *ref_tname;
55865627
const struct btf_type *t, *ref_t;
55875628
const struct btf_param *args;
@@ -5634,7 +5675,20 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
56345675

56355676
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
56365677
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])) {
56385692
const struct btf_type *reg_ref_t;
56395693
const struct btf *reg_btf;
56405694
const char *reg_ref_tname;
@@ -5650,14 +5704,9 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
56505704
if (reg->type == PTR_TO_BTF_ID) {
56515705
reg_btf = reg->btf;
56525706
reg_ref_id = reg->btf_id;
5653-
} else if (reg2btf_ids[reg->type]) {
5707+
} else {
56545708
reg_btf = btf_vmlinux;
56555709
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;
56615710
}
56625711

56635712
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,
56735722
reg_ref_tname);
56745723
return -EINVAL;
56755724
}
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;
56895725
} else if (ptr_to_mem_ok) {
56905726
const struct btf_type *resolve_ret;
56915727
u32 type_size;
56925728

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+
56935743
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
56945744
if (IS_ERR(resolve_ret)) {
56955745
bpf_log(log,
@@ -5702,6 +5752,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
57025752
if (check_mem_reg(env, reg, regno, type_size))
57035753
return -EINVAL;
57045754
} else {
5755+
bpf_log(log, "reg type unsupported for arg#%d %sfunction %s#%d\n", i,
5756+
is_kfunc ? "kernel " : "", func_name, func_id);
57055757
return -EINVAL;
57065758
}
57075759
}
@@ -5751,7 +5803,7 @@ int btf_check_kfunc_arg_match(struct bpf_verifier_env *env,
57515803
const struct btf *btf, u32 func_id,
57525804
struct bpf_reg_state *regs)
57535805
{
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);
57555807
}
57565808

57575809
/* Convert BTF of a function into bpf_reg_state if possible

0 commit comments

Comments
 (0)