Skip to content

Commit ba64e7d

Browse files
yonghong-songAlexei Starovoitov
authored andcommitted
bpf: btf: support proper non-jit func info
Commit 838e969 ("bpf: Introduce bpf_func_info") added bpf func info support. The userspace is able to get better ksym's for bpf programs with jit, and is able to print out func prototypes. For a program containing func-to-func calls, the existing implementation returns user specified number of function calls and BTF types if jit is enabled. If the jit is not enabled, it only returns the type for the main function. This is undesirable. Interpreter may still be used and we should keep feature identical regardless of whether jit is enabled or not. This patch fixed this discrepancy. Fixes: 838e969 ("bpf: Introduce bpf_func_info") Signed-off-by: Yonghong Song <yhs@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent d8f3e97 commit ba64e7d

File tree

5 files changed

+52
-46
lines changed

5 files changed

+52
-46
lines changed

include/linux/bpf.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ struct bpf_prog_aux {
299299
u32 max_pkt_offset;
300300
u32 stack_depth;
301301
u32 id;
302-
u32 func_cnt;
302+
u32 func_cnt; /* used by non-func prog as the number of func progs */
303+
u32 func_idx; /* 0 for non-func prog, the index in func array for func prog */
303304
bool offload_requested;
304305
struct bpf_prog **func;
305306
void *jit_data; /* JIT specific data. arch dependent */
@@ -317,7 +318,8 @@ struct bpf_prog_aux {
317318
#endif
318319
struct bpf_prog_offload *offload;
319320
struct btf *btf;
320-
u32 type_id; /* type id for this prog/func */
321+
struct bpf_func_info *func_info;
322+
u32 func_info_cnt;
321323
union {
322324
struct work_struct work;
323325
struct rcu_head rcu;

include/linux/bpf_verifier.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
204204
struct bpf_subprog_info {
205205
u32 start; /* insn idx of function entry point */
206206
u16 stack_depth; /* max. stack depth used by this function */
207-
u32 type_id; /* btf type_id for this subprog */
208207
};
209208

210209
/* single container for all structs

kernel/bpf/core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym)
411411

412412
/* prog->aux->name will be ignored if full btf name is available */
413413
if (prog->aux->btf) {
414-
type = btf_type_by_id(prog->aux->btf, prog->aux->type_id);
414+
type = btf_type_by_id(prog->aux->btf,
415+
prog->aux->func_info[prog->aux->func_idx].type_id);
415416
func_name = btf_name_by_offset(prog->aux->btf, type->name_off);
416417
snprintf(sym, (size_t)(end - sym), "_%s", func_name);
417418
return;

kernel/bpf/syscall.c

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
12141214
bpf_prog_free_id(prog, do_idr_lock);
12151215
bpf_prog_kallsyms_del_all(prog);
12161216
btf_put(prog->aux->btf);
1217+
kvfree(prog->aux->func_info);
12171218

12181219
call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
12191220
}
@@ -2219,46 +2220,28 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
22192220
}
22202221

22212222
if (prog->aux->btf) {
2223+
u32 krec_size = sizeof(struct bpf_func_info);
22222224
u32 ucnt, urec_size;
22232225

22242226
info.btf_id = btf_id(prog->aux->btf);
22252227

22262228
ucnt = info.func_info_cnt;
2227-
info.func_info_cnt = prog->aux->func_cnt ? : 1;
2229+
info.func_info_cnt = prog->aux->func_info_cnt;
22282230
urec_size = info.func_info_rec_size;
2229-
info.func_info_rec_size = sizeof(struct bpf_func_info);
2231+
info.func_info_rec_size = krec_size;
22302232
if (ucnt) {
22312233
/* expect passed-in urec_size is what the kernel expects */
22322234
if (urec_size != info.func_info_rec_size)
22332235
return -EINVAL;
22342236

22352237
if (bpf_dump_raw_ok()) {
2236-
struct bpf_func_info kern_finfo;
22372238
char __user *user_finfo;
2238-
u32 i, insn_offset;
22392239

22402240
user_finfo = u64_to_user_ptr(info.func_info);
2241-
if (prog->aux->func_cnt) {
2242-
ucnt = min_t(u32, info.func_info_cnt, ucnt);
2243-
insn_offset = 0;
2244-
for (i = 0; i < ucnt; i++) {
2245-
kern_finfo.insn_offset = insn_offset;
2246-
kern_finfo.type_id = prog->aux->func[i]->aux->type_id;
2247-
if (copy_to_user(user_finfo, &kern_finfo,
2248-
sizeof(kern_finfo)))
2249-
return -EFAULT;
2250-
2251-
/* func[i]->len holds the prog len */
2252-
insn_offset += prog->aux->func[i]->len;
2253-
user_finfo += urec_size;
2254-
}
2255-
} else {
2256-
kern_finfo.insn_offset = 0;
2257-
kern_finfo.type_id = prog->aux->type_id;
2258-
if (copy_to_user(user_finfo, &kern_finfo,
2259-
sizeof(kern_finfo)))
2260-
return -EFAULT;
2261-
}
2241+
ucnt = min_t(u32, info.func_info_cnt, ucnt);
2242+
if (copy_to_user(user_finfo, prog->aux->func_info,
2243+
krec_size * ucnt))
2244+
return -EFAULT;
22622245
} else {
22632246
info.func_info_cnt = 0;
22642247
}

kernel/bpf/verifier.c

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4650,7 +4650,7 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env,
46504650
{
46514651
u32 i, nfuncs, urec_size, min_size, prev_offset;
46524652
u32 krec_size = sizeof(struct bpf_func_info);
4653-
struct bpf_func_info krecord = {};
4653+
struct bpf_func_info *krecord = NULL;
46544654
const struct btf_type *type;
46554655
void __user *urecord;
46564656
struct btf *btf;
@@ -4682,6 +4682,12 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env,
46824682
urecord = u64_to_user_ptr(attr->func_info);
46834683
min_size = min_t(u32, krec_size, urec_size);
46844684

4685+
krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL | __GFP_NOWARN);
4686+
if (!krecord) {
4687+
ret = -ENOMEM;
4688+
goto free_btf;
4689+
}
4690+
46854691
for (i = 0; i < nfuncs; i++) {
46864692
ret = bpf_check_uarg_tail_zero(urecord, krec_size, urec_size);
46874693
if (ret) {
@@ -4696,59 +4702,69 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env,
46964702
goto free_btf;
46974703
}
46984704

4699-
if (copy_from_user(&krecord, urecord, min_size)) {
4705+
if (copy_from_user(&krecord[i], urecord, min_size)) {
47004706
ret = -EFAULT;
47014707
goto free_btf;
47024708
}
47034709

47044710
/* check insn_offset */
47054711
if (i == 0) {
4706-
if (krecord.insn_offset) {
4712+
if (krecord[i].insn_offset) {
47074713
verbose(env,
47084714
"nonzero insn_offset %u for the first func info record",
4709-
krecord.insn_offset);
4715+
krecord[i].insn_offset);
47104716
ret = -EINVAL;
47114717
goto free_btf;
47124718
}
4713-
} else if (krecord.insn_offset <= prev_offset) {
4719+
} else if (krecord[i].insn_offset <= prev_offset) {
47144720
verbose(env,
47154721
"same or smaller insn offset (%u) than previous func info record (%u)",
4716-
krecord.insn_offset, prev_offset);
4722+
krecord[i].insn_offset, prev_offset);
47174723
ret = -EINVAL;
47184724
goto free_btf;
47194725
}
47204726

4721-
if (env->subprog_info[i].start != krecord.insn_offset) {
4727+
if (env->subprog_info[i].start != krecord[i].insn_offset) {
47224728
verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n");
47234729
ret = -EINVAL;
47244730
goto free_btf;
47254731
}
47264732

47274733
/* check type_id */
4728-
type = btf_type_by_id(btf, krecord.type_id);
4734+
type = btf_type_by_id(btf, krecord[i].type_id);
47294735
if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) {
47304736
verbose(env, "invalid type id %d in func info",
4731-
krecord.type_id);
4737+
krecord[i].type_id);
47324738
ret = -EINVAL;
47334739
goto free_btf;
47344740
}
47354741

4736-
if (i == 0)
4737-
prog->aux->type_id = krecord.type_id;
4738-
env->subprog_info[i].type_id = krecord.type_id;
4739-
4740-
prev_offset = krecord.insn_offset;
4742+
prev_offset = krecord[i].insn_offset;
47414743
urecord += urec_size;
47424744
}
47434745

47444746
prog->aux->btf = btf;
4747+
prog->aux->func_info = krecord;
4748+
prog->aux->func_info_cnt = nfuncs;
47454749
return 0;
47464750

47474751
free_btf:
47484752
btf_put(btf);
4753+
kvfree(krecord);
47494754
return ret;
47504755
}
47514756

4757+
static void adjust_btf_func(struct bpf_verifier_env *env)
4758+
{
4759+
int i;
4760+
4761+
if (!env->prog->aux->func_info)
4762+
return;
4763+
4764+
for (i = 0; i < env->subprog_cnt; i++)
4765+
env->prog->aux->func_info[i].insn_offset = env->subprog_info[i].start;
4766+
}
4767+
47524768
/* check %cur's range satisfies %old's */
47534769
static bool range_within(struct bpf_reg_state *old,
47544770
struct bpf_reg_state *cur)
@@ -6043,15 +6059,17 @@ static int jit_subprogs(struct bpf_verifier_env *env)
60436059
if (bpf_prog_calc_tag(func[i]))
60446060
goto out_free;
60456061
func[i]->is_func = 1;
6062+
func[i]->aux->func_idx = i;
6063+
/* the btf and func_info will be freed only at prog->aux */
6064+
func[i]->aux->btf = prog->aux->btf;
6065+
func[i]->aux->func_info = prog->aux->func_info;
6066+
60466067
/* Use bpf_prog_F_tag to indicate functions in stack traces.
60476068
* Long term would need debug info to populate names
60486069
*/
60496070
func[i]->aux->name[0] = 'F';
60506071
func[i]->aux->stack_depth = env->subprog_info[i].stack_depth;
60516072
func[i]->jit_requested = 1;
6052-
/* the btf will be freed only at prog->aux */
6053-
func[i]->aux->btf = prog->aux->btf;
6054-
func[i]->aux->type_id = env->subprog_info[i].type_id;
60556073
func[i] = bpf_int_jit_compile(func[i]);
60566074
if (!func[i]->jited) {
60576075
err = -ENOTSUPP;
@@ -6572,6 +6590,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
65726590
convert_pseudo_ld_imm64(env);
65736591
}
65746592

6593+
if (ret == 0)
6594+
adjust_btf_func(env);
6595+
65756596
err_release_maps:
65766597
if (!env->prog->aux->used_maps)
65776598
/* if we didn't copy map pointers into bpf_prog_info, release

0 commit comments

Comments
 (0)