Skip to content

Commit 34747c4

Browse files
iamkafaiAlexei Starovoitov
authored andcommitted
bpf: Refactor btf_check_func_arg_match
This patch moved the subprog specific logic from btf_check_func_arg_match() to the new btf_check_subprog_arg_match(). The core logic is left in btf_check_func_arg_match() which will be reused later to check the kernel function call. The "if (!btf_type_is_ptr(t))" is checked first to improve the indentation which will be useful for a later patch. Some of the "btf_kind_str[]" usages is replaced with the shortcut "btf_type_str(t)". Signed-off-by: Martin KaFai Lau <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent e16301f commit 34747c4

File tree

4 files changed

+95
-77
lines changed

4 files changed

+95
-77
lines changed

include/linux/bpf.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,8 +1545,8 @@ int btf_distill_func_proto(struct bpf_verifier_log *log,
15451545
struct btf_func_model *m);
15461546

15471547
struct bpf_reg_state;
1548-
int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
1549-
struct bpf_reg_state *regs);
1548+
int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
1549+
struct bpf_reg_state *regs);
15501550
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
15511551
struct bpf_reg_state *reg);
15521552
int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog,

include/linux/btf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ static inline bool btf_type_is_enum(const struct btf_type *t)
141141
return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM;
142142
}
143143

144+
static inline bool btf_type_is_scalar(const struct btf_type *t)
145+
{
146+
return btf_type_is_int(t) || btf_type_is_enum(t);
147+
}
148+
144149
static inline bool btf_type_is_typedef(const struct btf_type *t)
145150
{
146151
return BTF_INFO_KIND(t->info) == BTF_KIND_TYPEDEF;

kernel/bpf/btf.c

Lines changed: 86 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4377,7 +4377,7 @@ static u8 bpf_ctx_convert_map[] = {
43774377
#undef BPF_LINK_TYPE
43784378

43794379
static const struct btf_member *
4380-
btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf,
4380+
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
43814381
const struct btf_type *t, enum bpf_prog_type prog_type,
43824382
int arg)
43834383
{
@@ -5362,122 +5362,135 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr
53625362
return btf_check_func_type_match(log, btf1, t1, btf2, t2);
53635363
}
53645364

5365-
/* Compare BTF of a function with given bpf_reg_state.
5366-
* Returns:
5367-
* EFAULT - there is a verifier bug. Abort verification.
5368-
* EINVAL - there is a type mismatch or BTF is not available.
5369-
* 0 - BTF matches with what bpf_reg_state expects.
5370-
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
5371-
*/
5372-
int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
5373-
struct bpf_reg_state *regs)
5365+
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
5366+
const struct btf *btf, u32 func_id,
5367+
struct bpf_reg_state *regs,
5368+
bool ptr_to_mem_ok)
53745369
{
53755370
struct bpf_verifier_log *log = &env->log;
5376-
struct bpf_prog *prog = env->prog;
5377-
struct btf *btf = prog->aux->btf;
5378-
const struct btf_param *args;
5371+
const char *func_name, *ref_tname;
53795372
const struct btf_type *t, *ref_t;
5380-
u32 i, nargs, btf_id, type_size;
5381-
const char *tname;
5382-
bool is_global;
5383-
5384-
if (!prog->aux->func_info)
5385-
return -EINVAL;
5386-
5387-
btf_id = prog->aux->func_info[subprog].type_id;
5388-
if (!btf_id)
5389-
return -EFAULT;
5390-
5391-
if (prog->aux->func_info_aux[subprog].unreliable)
5392-
return -EINVAL;
5373+
const struct btf_param *args;
5374+
u32 i, nargs;
53935375

5394-
t = btf_type_by_id(btf, btf_id);
5376+
t = btf_type_by_id(btf, func_id);
53955377
if (!t || !btf_type_is_func(t)) {
53965378
/* These checks were already done by the verifier while loading
53975379
* struct bpf_func_info
53985380
*/
5399-
bpf_log(log, "BTF of func#%d doesn't point to KIND_FUNC\n",
5400-
subprog);
5381+
bpf_log(log, "BTF of func_id %u doesn't point to KIND_FUNC\n",
5382+
func_id);
54015383
return -EFAULT;
54025384
}
5403-
tname = btf_name_by_offset(btf, t->name_off);
5385+
func_name = btf_name_by_offset(btf, t->name_off);
54045386

54055387
t = btf_type_by_id(btf, t->type);
54065388
if (!t || !btf_type_is_func_proto(t)) {
5407-
bpf_log(log, "Invalid BTF of func %s\n", tname);
5389+
bpf_log(log, "Invalid BTF of func %s\n", func_name);
54085390
return -EFAULT;
54095391
}
54105392
args = (const struct btf_param *)(t + 1);
54115393
nargs = btf_type_vlen(t);
54125394
if (nargs > MAX_BPF_FUNC_REG_ARGS) {
5413-
bpf_log(log, "Function %s has %d > %d args\n", tname, nargs,
5395+
bpf_log(log, "Function %s has %d > %d args\n", func_name, nargs,
54145396
MAX_BPF_FUNC_REG_ARGS);
5415-
goto out;
5397+
return -EINVAL;
54165398
}
54175399

5418-
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
54195400
/* check that BTF function arguments match actual types that the
54205401
* verifier sees.
54215402
*/
54225403
for (i = 0; i < nargs; i++) {
5423-
struct bpf_reg_state *reg = &regs[i + 1];
5404+
u32 regno = i + 1;
5405+
struct bpf_reg_state *reg = &regs[regno];
54245406

5425-
t = btf_type_by_id(btf, args[i].type);
5426-
while (btf_type_is_modifier(t))
5427-
t = btf_type_by_id(btf, t->type);
5428-
if (btf_type_is_int(t) || btf_type_is_enum(t)) {
5407+
t = btf_type_skip_modifiers(btf, args[i].type, NULL);
5408+
if (btf_type_is_scalar(t)) {
54295409
if (reg->type == SCALAR_VALUE)
54305410
continue;
5431-
bpf_log(log, "R%d is not a scalar\n", i + 1);
5432-
goto out;
5411+
bpf_log(log, "R%d is not a scalar\n", regno);
5412+
return -EINVAL;
54335413
}
5434-
if (btf_type_is_ptr(t)) {
5414+
5415+
if (!btf_type_is_ptr(t)) {
5416+
bpf_log(log, "Unrecognized arg#%d type %s\n",
5417+
i, btf_type_str(t));
5418+
return -EINVAL;
5419+
}
5420+
5421+
ref_t = btf_type_skip_modifiers(btf, t->type, NULL);
5422+
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
5423+
if (btf_get_prog_ctx_type(log, btf, t, env->prog->type, i)) {
54355424
/* If function expects ctx type in BTF check that caller
54365425
* is passing PTR_TO_CTX.
54375426
*/
5438-
if (btf_get_prog_ctx_type(log, btf, t, prog->type, i)) {
5439-
if (reg->type != PTR_TO_CTX) {
5440-
bpf_log(log,
5441-
"arg#%d expected pointer to ctx, but got %s\n",
5442-
i, btf_kind_str[BTF_INFO_KIND(t->info)]);
5443-
goto out;
5444-
}
5445-
if (check_ctx_reg(env, reg, i + 1))
5446-
goto out;
5447-
continue;
5427+
if (reg->type != PTR_TO_CTX) {
5428+
bpf_log(log,
5429+
"arg#%d expected pointer to ctx, but got %s\n",
5430+
i, btf_type_str(t));
5431+
return -EINVAL;
54485432
}
5433+
if (check_ctx_reg(env, reg, regno))
5434+
return -EINVAL;
5435+
} else if (ptr_to_mem_ok) {
5436+
const struct btf_type *resolve_ret;
5437+
u32 type_size;
54495438

5450-
if (!is_global)
5451-
goto out;
5452-
5453-
t = btf_type_skip_modifiers(btf, t->type, NULL);
5454-
5455-
ref_t = btf_resolve_size(btf, t, &type_size);
5456-
if (IS_ERR(ref_t)) {
5439+
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
5440+
if (IS_ERR(resolve_ret)) {
54575441
bpf_log(log,
5458-
"arg#%d reference type('%s %s') size cannot be determined: %ld\n",
5459-
i, btf_type_str(t), btf_name_by_offset(btf, t->name_off),
5460-
PTR_ERR(ref_t));
5461-
goto out;
5442+
"arg#%d reference type('%s %s') size cannot be determined: %ld\n",
5443+
i, btf_type_str(ref_t), ref_tname,
5444+
PTR_ERR(resolve_ret));
5445+
return -EINVAL;
54625446
}
54635447

5464-
if (check_mem_reg(env, reg, i + 1, type_size))
5465-
goto out;
5466-
5467-
continue;
5448+
if (check_mem_reg(env, reg, regno, type_size))
5449+
return -EINVAL;
5450+
} else {
5451+
return -EINVAL;
54685452
}
5469-
bpf_log(log, "Unrecognized arg#%d type %s\n",
5470-
i, btf_kind_str[BTF_INFO_KIND(t->info)]);
5471-
goto out;
54725453
}
5454+
54735455
return 0;
5474-
out:
5456+
}
5457+
5458+
/* Compare BTF of a function with given bpf_reg_state.
5459+
* Returns:
5460+
* EFAULT - there is a verifier bug. Abort verification.
5461+
* EINVAL - there is a type mismatch or BTF is not available.
5462+
* 0 - BTF matches with what bpf_reg_state expects.
5463+
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
5464+
*/
5465+
int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
5466+
struct bpf_reg_state *regs)
5467+
{
5468+
struct bpf_prog *prog = env->prog;
5469+
struct btf *btf = prog->aux->btf;
5470+
bool is_global;
5471+
u32 btf_id;
5472+
int err;
5473+
5474+
if (!prog->aux->func_info)
5475+
return -EINVAL;
5476+
5477+
btf_id = prog->aux->func_info[subprog].type_id;
5478+
if (!btf_id)
5479+
return -EFAULT;
5480+
5481+
if (prog->aux->func_info_aux[subprog].unreliable)
5482+
return -EINVAL;
5483+
5484+
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
5485+
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global);
5486+
54755487
/* Compiler optimizations can remove arguments from static functions
54765488
* or mismatched type can be passed into a global function.
54775489
* In such cases mark the function as unreliable from BTF point of view.
54785490
*/
5479-
prog->aux->func_info_aux[subprog].unreliable = true;
5480-
return -EINVAL;
5491+
if (err)
5492+
prog->aux->func_info_aux[subprog].unreliable = true;
5493+
return err;
54815494
}
54825495

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

kernel/bpf/verifier.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5365,7 +5365,7 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn
53655365
func_info_aux = env->prog->aux->func_info_aux;
53665366
if (func_info_aux)
53675367
is_global = func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
5368-
err = btf_check_func_arg_match(env, subprog, caller->regs);
5368+
err = btf_check_subprog_arg_match(env, subprog, caller->regs);
53695369
if (err == -EFAULT)
53705370
return err;
53715371
if (is_global) {
@@ -12288,7 +12288,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
1228812288
/* 1st arg to a function */
1228912289
regs[BPF_REG_1].type = PTR_TO_CTX;
1229012290
mark_reg_known_zero(env, regs, BPF_REG_1);
12291-
ret = btf_check_func_arg_match(env, subprog, regs);
12291+
ret = btf_check_subprog_arg_match(env, subprog, regs);
1229212292
if (ret == -EFAULT)
1229312293
/* unlikely verifier bug. abort.
1229412294
* ret == 0 and ret < 0 are sadly acceptable for

0 commit comments

Comments
 (0)