Skip to content

Commit f18c3d8

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
bpf: reuse subprog argument parsing logic for subprog call checks
Remove duplicated BTF parsing logic when it comes to subprog call check. Instead, use (potentially cached) results of btf_prepare_func_args() to abstract away expectations of each subprog argument in generic terms (e.g., "this is pointer to context", or "this is a pointer to memory of size X"), and then use those simple high-level argument type expectations to validate actual register states to check if they match expectations. Acked-by: Eduard Zingerman <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent c5a7244 commit f18c3d8

File tree

2 files changed

+31
-81
lines changed

2 files changed

+31
-81
lines changed

kernel/bpf/verifier.c

Lines changed: 30 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9249,101 +9249,54 @@ static int setup_func_entry(struct bpf_verifier_env *env, int subprog, int calls
92499249
return err;
92509250
}
92519251

9252-
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
9253-
const struct btf *btf, u32 func_id,
9254-
struct bpf_reg_state *regs,
9255-
bool ptr_to_mem_ok)
9252+
static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
9253+
const struct btf *btf,
9254+
struct bpf_reg_state *regs)
92569255
{
9257-
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
9256+
struct bpf_subprog_info *sub = subprog_info(env, subprog);
92589257
struct bpf_verifier_log *log = &env->log;
9259-
const char *func_name, *ref_tname;
9260-
const struct btf_type *t, *ref_t;
9261-
const struct btf_param *args;
9262-
u32 i, nargs, ref_id;
9258+
u32 i;
92639259
int ret;
92649260

9265-
t = btf_type_by_id(btf, func_id);
9266-
if (!t || !btf_type_is_func(t)) {
9267-
/* These checks were already done by the verifier while loading
9268-
* struct bpf_func_info or in add_kfunc_call().
9269-
*/
9270-
bpf_log(log, "BTF of func_id %u doesn't point to KIND_FUNC\n",
9271-
func_id);
9272-
return -EFAULT;
9273-
}
9274-
func_name = btf_name_by_offset(btf, t->name_off);
9275-
9276-
t = btf_type_by_id(btf, t->type);
9277-
if (!t || !btf_type_is_func_proto(t)) {
9278-
bpf_log(log, "Invalid BTF of func %s\n", func_name);
9279-
return -EFAULT;
9280-
}
9281-
args = (const struct btf_param *)(t + 1);
9282-
nargs = btf_type_vlen(t);
9283-
if (nargs > MAX_BPF_FUNC_REG_ARGS) {
9284-
bpf_log(log, "Function %s has %d > %d args\n", func_name, nargs,
9285-
MAX_BPF_FUNC_REG_ARGS);
9286-
return -EINVAL;
9287-
}
9261+
ret = btf_prepare_func_args(env, subprog);
9262+
if (ret)
9263+
return ret;
92889264

92899265
/* check that BTF function arguments match actual types that the
92909266
* verifier sees.
92919267
*/
9292-
for (i = 0; i < nargs; i++) {
9293-
enum bpf_arg_type arg_type = ARG_DONTCARE;
9268+
for (i = 0; i < sub->arg_cnt; i++) {
92949269
u32 regno = i + 1;
92959270
struct bpf_reg_state *reg = &regs[regno];
9271+
struct bpf_subprog_arg_info *arg = &sub->args[i];
92969272

9297-
t = btf_type_skip_modifiers(btf, args[i].type, NULL);
9298-
if (btf_type_is_scalar(t)) {
9299-
if (reg->type == SCALAR_VALUE)
9300-
continue;
9301-
bpf_log(log, "R%d is not a scalar\n", regno);
9302-
return -EINVAL;
9303-
}
9304-
9305-
if (!btf_type_is_ptr(t)) {
9306-
bpf_log(log, "Unrecognized arg#%d type %s\n",
9307-
i, btf_type_str(t));
9308-
return -EINVAL;
9309-
}
9310-
9311-
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
9312-
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
9313-
9314-
ret = check_func_arg_reg_off(env, reg, regno, arg_type);
9315-
if (ret < 0)
9316-
return ret;
9317-
9318-
if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
9273+
if (arg->arg_type == ARG_ANYTHING) {
9274+
if (reg->type != SCALAR_VALUE) {
9275+
bpf_log(log, "R%d is not a scalar\n", regno);
9276+
return -EINVAL;
9277+
}
9278+
} else if (arg->arg_type == ARG_PTR_TO_CTX) {
9279+
ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
9280+
if (ret < 0)
9281+
return ret;
93199282
/* If function expects ctx type in BTF check that caller
93209283
* is passing PTR_TO_CTX.
93219284
*/
93229285
if (reg->type != PTR_TO_CTX) {
9323-
bpf_log(log,
9324-
"arg#%d expected pointer to ctx, but got %s\n",
9325-
i, btf_type_str(t));
9326-
return -EINVAL;
9327-
}
9328-
} else if (ptr_to_mem_ok) {
9329-
const struct btf_type *resolve_ret;
9330-
u32 type_size;
9331-
9332-
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
9333-
if (IS_ERR(resolve_ret)) {
9334-
bpf_log(log,
9335-
"arg#%d reference type('%s %s') size cannot be determined: %ld\n",
9336-
i, btf_type_str(ref_t), ref_tname,
9337-
PTR_ERR(resolve_ret));
9286+
bpf_log(log, "arg#%d expects pointer to ctx\n", i);
93389287
return -EINVAL;
93399288
}
9289+
} else if (base_type(arg->arg_type) == ARG_PTR_TO_MEM) {
9290+
ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
9291+
if (ret < 0)
9292+
return ret;
93409293

9341-
if (check_mem_reg(env, reg, regno, type_size))
9294+
if (check_mem_reg(env, reg, regno, arg->mem_size))
93429295
return -EINVAL;
93439296
} else {
9344-
bpf_log(log, "reg type unsupported for arg#%d function %s#%d\n", i,
9345-
func_name, func_id);
9346-
return -EINVAL;
9297+
bpf_log(log, "verifier bug: unrecognized arg#%d type %d\n",
9298+
i, arg->arg_type);
9299+
return -EFAULT;
93479300
}
93489301
}
93499302

@@ -9358,11 +9311,10 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
93589311
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
93599312
*/
93609313
static int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
9361-
struct bpf_reg_state *regs)
9314+
struct bpf_reg_state *regs)
93629315
{
93639316
struct bpf_prog *prog = env->prog;
93649317
struct btf *btf = prog->aux->btf;
9365-
bool is_global;
93669318
u32 btf_id;
93679319
int err;
93689320

@@ -9376,9 +9328,7 @@ static int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
93769328
if (prog->aux->func_info_aux[subprog].unreliable)
93779329
return -EINVAL;
93789330

9379-
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
9380-
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global);
9381-
9331+
err = btf_check_func_arg_match(env, subprog, btf, regs);
93829332
/* Compiler optimizations can remove arguments from static functions
93839333
* or mismatched type can be passed into a global function.
93849334
* In such cases mark the function as unreliable from BTF point of view.

tools/testing/selftests/bpf/progs/test_global_func5.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ int f3(int val, struct __sk_buff *skb)
2626
}
2727

2828
SEC("tc")
29-
__failure __msg("expected pointer to ctx, but got PTR")
29+
__failure __msg("expects pointer to ctx")
3030
int global_func5(struct __sk_buff *skb)
3131
{
3232
return f1(skb) + f2(2, skb) + f3(3, skb);

0 commit comments

Comments
 (0)