Skip to content

Commit aaa619e

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
bpf: Refactor check_btf_func and split into two phases
This patch splits the check_btf_info's check_btf_func check into two separate phases. The first phase sets up the BTF and prepares func_info, but does not perform any validation of required invariants for subprogs just yet. This is left to the second phase, which happens where check_btf_info executes currently, and performs the line_info and CO-RE relocation. The reason to perform this split is to obtain the userspace supplied func_info information before we perform the add_subprog call, where we would now require finding and adding subprogs that may not have a bpf_pseudo_call or bpf_pseudo_func instruction in the program. We require this as we want to enable userspace to supply exception callbacks that can override the default hidden subprogram generated by the verifier (which performs a hardcoded action). In such a case, the exception callback may never be referenced in an instruction, but will still be suitably annotated (by way of BTF declaration tags). For finding this exception callback, we would require the program's BTF information, and the supplied func_info information which maps BTF type IDs to subprograms. Since the exception callback won't actually be referenced through instructions, later checks in check_cfg and do_check_subprogs will not verify the subprog. This means that add_subprog needs to add them in the add_subprog_and_kfunc phase before we move forward, which is why the BTF and func_info are required at that point. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent f18b03f commit aaa619e

File tree

1 file changed

+100
-28
lines changed

1 file changed

+100
-28
lines changed

kernel/bpf/verifier.c

Lines changed: 100 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15115,20 +15115,18 @@ static int check_abnormal_return(struct bpf_verifier_env *env)
1511515115
#define MIN_BPF_FUNCINFO_SIZE 8
1511615116
#define MAX_FUNCINFO_REC_SIZE 252
1511715117

15118-
static int check_btf_func(struct bpf_verifier_env *env,
15119-
const union bpf_attr *attr,
15120-
bpfptr_t uattr)
15118+
static int check_btf_func_early(struct bpf_verifier_env *env,
15119+
const union bpf_attr *attr,
15120+
bpfptr_t uattr)
1512115121
{
15122-
const struct btf_type *type, *func_proto, *ret_type;
15123-
u32 i, nfuncs, urec_size, min_size;
1512415122
u32 krec_size = sizeof(struct bpf_func_info);
15123+
const struct btf_type *type, *func_proto;
15124+
u32 i, nfuncs, urec_size, min_size;
1512515125
struct bpf_func_info *krecord;
15126-
struct bpf_func_info_aux *info_aux = NULL;
1512715126
struct bpf_prog *prog;
1512815127
const struct btf *btf;
15129-
bpfptr_t urecord;
1513015128
u32 prev_offset = 0;
15131-
bool scalar_return;
15129+
bpfptr_t urecord;
1513215130
int ret = -ENOMEM;
1513315131

1513415132
nfuncs = attr->func_info_cnt;
@@ -15138,11 +15136,6 @@ static int check_btf_func(struct bpf_verifier_env *env,
1513815136
return 0;
1513915137
}
1514015138

15141-
if (nfuncs != env->subprog_cnt) {
15142-
verbose(env, "number of funcs in func_info doesn't match number of subprogs\n");
15143-
return -EINVAL;
15144-
}
15145-
1514615139
urec_size = attr->func_info_rec_size;
1514715140
if (urec_size < MIN_BPF_FUNCINFO_SIZE ||
1514815141
urec_size > MAX_FUNCINFO_REC_SIZE ||
@@ -15160,9 +15153,6 @@ static int check_btf_func(struct bpf_verifier_env *env,
1516015153
krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL | __GFP_NOWARN);
1516115154
if (!krecord)
1516215155
return -ENOMEM;
15163-
info_aux = kcalloc(nfuncs, sizeof(*info_aux), GFP_KERNEL | __GFP_NOWARN);
15164-
if (!info_aux)
15165-
goto err_free;
1516615156

1516715157
for (i = 0; i < nfuncs; i++) {
1516815158
ret = bpf_check_uarg_tail_zero(urecord, krec_size, urec_size);
@@ -15201,24 +15191,87 @@ static int check_btf_func(struct bpf_verifier_env *env,
1520115191
goto err_free;
1520215192
}
1520315193

15204-
if (env->subprog_info[i].start != krecord[i].insn_off) {
15205-
verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n");
15206-
goto err_free;
15207-
}
15208-
1520915194
/* check type_id */
1521015195
type = btf_type_by_id(btf, krecord[i].type_id);
1521115196
if (!type || !btf_type_is_func(type)) {
1521215197
verbose(env, "invalid type id %d in func info",
1521315198
krecord[i].type_id);
1521415199
goto err_free;
1521515200
}
15216-
info_aux[i].linkage = BTF_INFO_VLEN(type->info);
1521715201

1521815202
func_proto = btf_type_by_id(btf, type->type);
1521915203
if (unlikely(!func_proto || !btf_type_is_func_proto(func_proto)))
1522015204
/* btf_func_check() already verified it during BTF load */
1522115205
goto err_free;
15206+
15207+
prev_offset = krecord[i].insn_off;
15208+
bpfptr_add(&urecord, urec_size);
15209+
}
15210+
15211+
prog->aux->func_info = krecord;
15212+
prog->aux->func_info_cnt = nfuncs;
15213+
return 0;
15214+
15215+
err_free:
15216+
kvfree(krecord);
15217+
return ret;
15218+
}
15219+
15220+
static int check_btf_func(struct bpf_verifier_env *env,
15221+
const union bpf_attr *attr,
15222+
bpfptr_t uattr)
15223+
{
15224+
const struct btf_type *type, *func_proto, *ret_type;
15225+
u32 i, nfuncs, urec_size, min_size;
15226+
u32 krec_size = sizeof(struct bpf_func_info);
15227+
struct bpf_func_info *krecord;
15228+
struct bpf_func_info_aux *info_aux = NULL;
15229+
struct bpf_prog *prog;
15230+
const struct btf *btf;
15231+
bpfptr_t urecord;
15232+
u32 prev_offset = 0;
15233+
bool scalar_return;
15234+
int ret = -ENOMEM;
15235+
15236+
nfuncs = attr->func_info_cnt;
15237+
if (!nfuncs) {
15238+
if (check_abnormal_return(env))
15239+
return -EINVAL;
15240+
return 0;
15241+
}
15242+
if (nfuncs != env->subprog_cnt) {
15243+
verbose(env, "number of funcs in func_info doesn't match number of subprogs\n");
15244+
return -EINVAL;
15245+
}
15246+
15247+
urec_size = attr->func_info_rec_size;
15248+
15249+
prog = env->prog;
15250+
btf = prog->aux->btf;
15251+
15252+
urecord = make_bpfptr(attr->func_info, uattr.is_kernel);
15253+
min_size = min_t(u32, krec_size, urec_size);
15254+
15255+
krecord = prog->aux->func_info;
15256+
info_aux = kcalloc(nfuncs, sizeof(*info_aux), GFP_KERNEL | __GFP_NOWARN);
15257+
if (!info_aux)
15258+
return -ENOMEM;
15259+
15260+
for (i = 0; i < nfuncs; i++) {
15261+
/* check insn_off */
15262+
ret = -EINVAL;
15263+
15264+
if (env->subprog_info[i].start != krecord[i].insn_off) {
15265+
verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n");
15266+
goto err_free;
15267+
}
15268+
15269+
/* Already checked type_id */
15270+
type = btf_type_by_id(btf, krecord[i].type_id);
15271+
info_aux[i].linkage = BTF_INFO_VLEN(type->info);
15272+
/* Already checked func_proto */
15273+
func_proto = btf_type_by_id(btf, type->type);
15274+
1522215275
ret_type = btf_type_skip_modifiers(btf, func_proto->type, NULL);
1522315276
scalar_return =
1522415277
btf_type_is_small_int(ret_type) || btf_is_any_enum(ret_type);
@@ -15235,13 +15288,10 @@ static int check_btf_func(struct bpf_verifier_env *env,
1523515288
bpfptr_add(&urecord, urec_size);
1523615289
}
1523715290

15238-
prog->aux->func_info = krecord;
15239-
prog->aux->func_info_cnt = nfuncs;
1524015291
prog->aux->func_info_aux = info_aux;
1524115292
return 0;
1524215293

1524315294
err_free:
15244-
kvfree(krecord);
1524515295
kfree(info_aux);
1524615296
return ret;
1524715297
}
@@ -15459,9 +15509,9 @@ static int check_core_relo(struct bpf_verifier_env *env,
1545915509
return err;
1546015510
}
1546115511

15462-
static int check_btf_info(struct bpf_verifier_env *env,
15463-
const union bpf_attr *attr,
15464-
bpfptr_t uattr)
15512+
static int check_btf_info_early(struct bpf_verifier_env *env,
15513+
const union bpf_attr *attr,
15514+
bpfptr_t uattr)
1546515515
{
1546615516
struct btf *btf;
1546715517
int err;
@@ -15481,6 +15531,24 @@ static int check_btf_info(struct bpf_verifier_env *env,
1548115531
}
1548215532
env->prog->aux->btf = btf;
1548315533

15534+
err = check_btf_func_early(env, attr, uattr);
15535+
if (err)
15536+
return err;
15537+
return 0;
15538+
}
15539+
15540+
static int check_btf_info(struct bpf_verifier_env *env,
15541+
const union bpf_attr *attr,
15542+
bpfptr_t uattr)
15543+
{
15544+
int err;
15545+
15546+
if (!attr->func_info_cnt && !attr->line_info_cnt) {
15547+
if (check_abnormal_return(env))
15548+
return -EINVAL;
15549+
return 0;
15550+
}
15551+
1548415552
err = check_btf_func(env, attr, uattr);
1548515553
if (err)
1548615554
return err;
@@ -19990,6 +20058,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
1999020058
if (!env->explored_states)
1999120059
goto skip_full_check;
1999220060

20061+
ret = check_btf_info_early(env, attr, uattr);
20062+
if (ret < 0)
20063+
goto skip_full_check;
20064+
1999320065
ret = add_subprog_and_kfunc(env);
1999420066
if (ret < 0)
1999520067
goto skip_full_check;

0 commit comments

Comments
 (0)