bpf: Free the subprog jump tables once the CFG passes are done

The jump tables which compute_subprog_jts() builds are only read through
bpf_insn_successors() once CFG discovery is done. Its last caller is
bpf_compute_scev(), which runs after bpf_compute_live_registers(), so
free the tables right after it instead of keeping them until the verifier
environment is torn down. With large insn_array maps, this also drops them
before do_check() starts to allocate states.

Dead code removal runs after do_check(), so a removed subprogram no longer
owns a table and adjust_subprog_starts_after_remove() can go back to not
caring about the table pointers.

Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261016155559.652461-1-daniel@iogearbox.net
This commit is contained in:
Daniel Borkmann 2026-10-16 17:55:59 +02:00 committed by Alexei Starovoitov
parent b4e14f4737
commit d2141481a7
No known key found for this signature in database
2 changed files with 3 additions and 8 deletions

View File

@ -477,11 +477,7 @@ static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,
if (j > i) {
struct bpf_prog_aux *aux = env->prog->aux;
int move, k;
/* The removed subprogs own their jump tables. */
for (k = i; k < j; k++)
kvfree(env->subprog_info[k].jt);
int move;
/* move fake 'exit' subprog as well */
move = env->subprog_cnt + 1 - j;
@ -489,9 +485,6 @@ static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,
memmove(env->subprog_info + i,
env->subprog_info + j,
sizeof(*env->subprog_info) * move);
/* The vacated tail still holds copies of the moved entries. */
memset(env->subprog_info + i + move, 0,
sizeof(*env->subprog_info) * (j - i));
env->subprog_cnt -= j - i;
/* remove func_info and its aux */

View File

@ -23487,6 +23487,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
if (ret < 0)
goto skip_full_check;
bpf_free_subprog_jts(env);
ret = mark_fastcall_patterns(env);
if (ret < 0)
goto skip_full_check;