mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
bpf: Correct Program Structure diagnostic context
Program Structure reports have two attribution gaps. A missing jump table is reported at the beginning of its subprogram rather than at the gotox that needs the table, and the subprogram-layout checks run before func_info and line_info are validated and installed, so their reports cannot name the source function or line. Report the missing jump table at the gotox instruction that looks it up, rather than at the start of its subprogram. func_info and line_info validation only needs the subprogram boundaries found by add_subprogs() and the LD_ABS and tail-call properties that check_subprogs() collects while scanning instructions; it does not depend on the layout checks themselves. Split the property collection into its own nested subprogram and instruction scan, together with the program's callx marker, and run bpf_check_btf_info() before check_subprogs(). The jump-boundary and fallthrough reports then carry validated source information without changing either check. CO-RE relocations are unaffected: commitc26e97721b("bpf: Apply CO-RE relocations before subprogram validation") applies them before add_subprogs(), and they stay there. Only the func_info and line_info validation moves. Fixes:a8f4278353("bpf: Report Program Structure CFG errors") Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/cf2f420c2b21de440a7dc51b1565c0f06d4b539640ee5c03384e5d77bcfb5686@mail.kernel.org/ Link: https://lore.kernel.org/bpf/20260926133048.2962553-3-memxor@gmail.com
This commit is contained in:
parent
8295510622
commit
d91052063b
|
|
@ -393,7 +393,7 @@ subprog_jt(int t, struct bpf_verifier_env *env)
|
|||
if (!subprog->jt) {
|
||||
verbose(env, "no jump tables found for subprog starting at %u\n", subprog_start);
|
||||
bpf_diag_program_structure(
|
||||
env, subprog_start, "missing jump table",
|
||||
env, t, "missing jump table",
|
||||
"Make sure subprograms containing gotox instructions are accompanied by jump tables referencing these subprograms.",
|
||||
"No jump table was found for the subprogram that starts at instruction %u.",
|
||||
subprog_start);
|
||||
|
|
|
|||
|
|
@ -3107,6 +3107,34 @@ static int add_kfuncs(struct bpf_verifier_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void find_subprog_properties(struct bpf_verifier_env *env)
|
||||
{
|
||||
struct bpf_subprog_info *subprog = env->subprog_info;
|
||||
struct bpf_insn *insn = env->prog->insnsi;
|
||||
int cur_subprog;
|
||||
|
||||
for (cur_subprog = 0; cur_subprog < env->subprog_cnt; cur_subprog++) {
|
||||
int i;
|
||||
|
||||
for (i = subprog[cur_subprog].start;
|
||||
i < subprog[cur_subprog + 1].start; i++) {
|
||||
u8 code = insn[i].code;
|
||||
|
||||
if (code == (BPF_JMP | BPF_CALL) &&
|
||||
insn[i].src_reg == 0 &&
|
||||
insn[i].imm == BPF_FUNC_tail_call) {
|
||||
subprog[cur_subprog].has_tail_call = true;
|
||||
subprog[cur_subprog].tail_call_reachable = true;
|
||||
}
|
||||
if (BPF_CLASS(code) == BPF_LD &&
|
||||
(BPF_MODE(code) == BPF_ABS || BPF_MODE(code) == BPF_IND))
|
||||
subprog[cur_subprog].has_ld_abs = true;
|
||||
if (bpf_is_callx(&insn[i]))
|
||||
env->has_callx = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_subprogs(struct bpf_verifier_env *env)
|
||||
{
|
||||
int i, subprog_start, subprog_end, off, cur_subprog = 0;
|
||||
|
|
@ -3120,17 +3148,6 @@ static int check_subprogs(struct bpf_verifier_env *env)
|
|||
for (i = 0; i < insn_cnt; i++) {
|
||||
u8 code = insn[i].code;
|
||||
|
||||
if (code == (BPF_JMP | BPF_CALL) &&
|
||||
insn[i].src_reg == 0 &&
|
||||
insn[i].imm == BPF_FUNC_tail_call) {
|
||||
subprog[cur_subprog].has_tail_call = true;
|
||||
subprog[cur_subprog].tail_call_reachable = true;
|
||||
}
|
||||
if (BPF_CLASS(code) == BPF_LD &&
|
||||
(BPF_MODE(code) == BPF_ABS || BPF_MODE(code) == BPF_IND))
|
||||
subprog[cur_subprog].has_ld_abs = true;
|
||||
if (bpf_is_callx(&insn[i]))
|
||||
env->has_callx = true;
|
||||
if (BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32)
|
||||
goto next;
|
||||
if (BPF_OP(code) == BPF_CALL)
|
||||
|
|
@ -3154,9 +3171,10 @@ static int check_subprogs(struct bpf_verifier_env *env)
|
|||
}
|
||||
next:
|
||||
if (i == subprog_end - 1) {
|
||||
/* to avoid fall-through from one subprog into another
|
||||
/*
|
||||
* To avoid fall-through from one subprog into another,
|
||||
* the last insn of the subprog should be either exit
|
||||
* or unconditional jump back or bpf_throw call
|
||||
* or unconditional jump back or bpf_throw call.
|
||||
*/
|
||||
if (code != (BPF_JMP | BPF_EXIT) &&
|
||||
code != (BPF_JMP32 | BPF_JA) &&
|
||||
|
|
@ -22511,17 +22529,19 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
|
|||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
/* Discover all subprograms before validating their layout and BTF. */
|
||||
/* Discover all subprograms and collect the properties needed by BTF validation. */
|
||||
ret = add_subprogs(env);
|
||||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
ret = check_subprogs(env);
|
||||
find_subprog_properties(env);
|
||||
|
||||
/* Validate BTF before reporting subprogram layout errors. */
|
||||
ret = bpf_check_btf_info(env, attr, uattr);
|
||||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
/* Validate BTF against the complete subprogram layout. */
|
||||
ret = bpf_check_btf_info(env, attr, uattr);
|
||||
ret = check_subprogs(env);
|
||||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user