diff options
| author | Daniel Borkmann <daniel@iogearbox.net> | 2026-09-25 19:52:34 +0200 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-09-25 21:02:31 +0000 |
| commit | c48a91c049fd98fcde54880a24c51b9a05f7e185 (patch) | |
| tree | 6447cb28fd35172a44d4e6d45c5cd4a3642f228a /kernel | |
| parent | 19581372dd81f3337bb672a437e56050a3ea41cb (diff) | |
| download | linux-c48a91c049fd98fcde54880a24c51b9a05f7e185.tar.gz linux-c48a91c049fd98fcde54880a24c51b9a05f7e185.zip | |
bpf: Don't remove indirect jump targets in the nop removal pass
bpf_opt_remove_nops() drops every ja +0 and may_goto +0 unconditionally.
A gotox target may itself be such a transparent nop: it is a verified
entry of an insn array jump table that is reachable at run time through
the indirect jump. bpf_insn_array_adjust_after_remove() marks it as
INSN_DELETED instead, and bpf_insn_array_ready() skips INSN_DELETED
entries, so the program loads with a hole in its jump table. The x86
JIT, for example, lowers gotox to a raw indirect jump, so executing
that index jumps to the zeroed ips[] slot, that is, to address 0.
Fix by keeping an indirect jump target in place.
Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps")
Reported-by: Sandipan Roy <saroy@redhat.com>
Reported-by: James Burton <jamesburton@meta.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Anton Protopopov <a.s.protopopov@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260925175244.1136329-8-daniel@iogearbox.net
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/fixups.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index adc254b1a646..d4e54fa42dae 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -727,6 +727,7 @@ int bpf_opt_remove_dead_code(struct bpf_verifier_env *env) int bpf_opt_remove_nops(struct bpf_verifier_env *env) { + struct bpf_insn_aux_data *aux = env->insn_aux_data; struct bpf_insn *insn = env->prog->insnsi; int insn_cnt = env->prog->len; bool is_may_goto_0, is_ja; @@ -738,6 +739,8 @@ int bpf_opt_remove_nops(struct bpf_verifier_env *env) if (!is_may_goto_0 && !is_ja) continue; + if (aux[i].indirect_target) + continue; err = verifier_remove_insns(env, i, 1); if (err) |
