Skip to content

Commit 4f7bc83

Browse files
puranjaymohanAlexei Starovoitov
authored andcommitted
bpf: verifier: Move desc->imm setup to sort_kfunc_descs_by_imm_off()
Metadata about a kfunc call is added to the kfunc_tab in add_kfunc_call() but the call instruction itself could get removed by opt_remove_dead_code() later if it is not reachable. If the call instruction is removed, specialize_kfunc() is never called for it and the desc->imm in the kfunc_tab is never initialized for this kfunc call. In this case, sort_kfunc_descs_by_imm_off(env->prog); in do_misc_fixups() doesn't sort the table correctly. This is a problem for s390 as its JIT uses this table to find the addresses for kfuncs, and if this table is not sorted properly, JIT may fail to find addresses for valid kfunc calls. This was exposed by: commit d869d56 ("bpf: verifier: refactor kfunc specialization") as before this commit, desc->imm was initialised in add_kfunc_call() which happens before dead code elimination. Move desc->imm setup down to sort_kfunc_descs_by_imm_off(), this fixes the problem and also saves us from having the same logic in add_kfunc_call() and specialize_kfunc(). Suggested-by: Eduard Zingerman <[email protected]> Signed-off-by: Puranjay Mohan <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent a4d31f4 commit 4f7bc83

File tree

1 file changed

+35
-19
lines changed

1 file changed

+35
-19
lines changed

kernel/bpf/verifier.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3391,16 +3391,43 @@ static int kfunc_desc_cmp_by_imm_off(const void *a, const void *b)
33913391
return 0;
33923392
}
33933393

3394-
static void sort_kfunc_descs_by_imm_off(struct bpf_prog *prog)
3394+
static int set_kfunc_desc_imm(struct bpf_verifier_env *env, struct bpf_kfunc_desc *desc)
3395+
{
3396+
unsigned long call_imm;
3397+
3398+
if (bpf_jit_supports_far_kfunc_call()) {
3399+
call_imm = desc->func_id;
3400+
} else {
3401+
call_imm = BPF_CALL_IMM(desc->addr);
3402+
/* Check whether the relative offset overflows desc->imm */
3403+
if ((unsigned long)(s32)call_imm != call_imm) {
3404+
verbose(env, "address of kernel func_id %u is out of range\n",
3405+
desc->func_id);
3406+
return -EINVAL;
3407+
}
3408+
}
3409+
desc->imm = call_imm;
3410+
return 0;
3411+
}
3412+
3413+
static int sort_kfunc_descs_by_imm_off(struct bpf_verifier_env *env)
33953414
{
33963415
struct bpf_kfunc_desc_tab *tab;
3416+
int i, err;
33973417

3398-
tab = prog->aux->kfunc_tab;
3418+
tab = env->prog->aux->kfunc_tab;
33993419
if (!tab)
3400-
return;
3420+
return 0;
3421+
3422+
for (i = 0; i < tab->nr_descs; i++) {
3423+
err = set_kfunc_desc_imm(env, &tab->descs[i]);
3424+
if (err)
3425+
return err;
3426+
}
34013427

34023428
sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
34033429
kfunc_desc_cmp_by_imm_off, NULL);
3430+
return 0;
34043431
}
34053432

34063433
bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
@@ -22323,10 +22350,10 @@ static int specialize_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_desc
2232322350
bool is_rdonly;
2232422351
u32 func_id = desc->func_id;
2232522352
u16 offset = desc->offset;
22326-
unsigned long addr = desc->addr, call_imm;
22353+
unsigned long addr = desc->addr;
2232722354

2232822355
if (offset) /* return if module BTF is used */
22329-
goto set_imm;
22356+
return 0;
2233022357

2233122358
if (bpf_dev_bound_kfunc_id(func_id)) {
2233222359
xdp_kfunc = bpf_dev_bound_resolve_kfunc(prog, func_id);
@@ -22354,19 +22381,6 @@ static int specialize_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_desc
2235422381
if (!env->insn_aux_data[insn_idx].non_sleepable)
2235522382
addr = (unsigned long)bpf_dynptr_from_file_sleepable;
2235622383
}
22357-
22358-
set_imm:
22359-
if (bpf_jit_supports_far_kfunc_call()) {
22360-
call_imm = func_id;
22361-
} else {
22362-
call_imm = BPF_CALL_IMM(addr);
22363-
/* Check whether the relative offset overflows desc->imm */
22364-
if ((unsigned long)(s32)call_imm != call_imm) {
22365-
verbose(env, "address of kernel func_id %u is out of range\n", func_id);
22366-
return -EINVAL;
22367-
}
22368-
}
22369-
desc->imm = call_imm;
2237022384
desc->addr = addr;
2237122385
return 0;
2237222386
}
@@ -23444,7 +23458,9 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
2344423458
}
2344523459
}
2344623460

23447-
sort_kfunc_descs_by_imm_off(env->prog);
23461+
ret = sort_kfunc_descs_by_imm_off(env);
23462+
if (ret)
23463+
return ret;
2344823464

2344923465
return 0;
2345023466
}

0 commit comments

Comments
 (0)