From: Qiliang Yuan <odys.yuan@gmail.com>
To: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
John Fastabend <john.fastabend@gmail.com>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
Shuah Khan <shuah@kernel.org>
Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org,
Qiliang Yuan <odys.yuan@gmail.com>
Subject: [PATCH bpf-next v2 00/22] bpf: Replace bpf_patch_insn_data() with a list of deferred patches
Date: Fri, 30 Oct 2026 07:51:45 -0400 [thread overview]
Message-ID: <20261030-bpf-verifier-patch-batch-v2-0-55cd43439f7c@gmail.com> (raw)
bpf_patch_insn_data() and bpf_patch_insn_single() apply a patch right
away: they move the tail of the instruction and aux data arrays and walk
the whole program to fix up branches and every table that names
instructions. Removing instructions works the same way.
A pass that patches M instructions of an N instruction program does
O(N * M) work. Eduard pointed out that this takes a large share of the
time to load pyperf180 [1], and with bpf_jit_harden=2 or many nops to
remove it gets to minutes.
Replace them with a list that a pass fills with patches and commits
once in O(N + inserted instructions). Following the layout of Jiong's
RFC [2], the list goes to core.c and the verifier side to fixups.c,
then each pass moves over and the last patch removes the old code. As
Andrii suggested there, map every old index to a new one once and
relocate all jumps through that map. Since passes queue patches in
increasing order of the instruction they replace, keep the list in a
sorted array instead of a linked list.
1-3 the patch list in core.c and in the verifier
4-6 bpf_do_misc_fixups(), gotol for a backward may_goto
7-9 removal of instructions, dead code and nops
10 zext
11-13 patching an instruction twice, inserting in front of one
14-17 ctx accesses, may_goto counter setup, hidden subprog, bpf_loop()
18-19 commit without a verifier env, constant blinding
20 removal of the old code
21-22 selftests
Load times on an x86_64 VM with 32 vCPUs, the base commit below with
and without the series, measured in one round: perf stat -r30 --
veristat -q <obj> averaged over two runs, -r10 for BPF_F_TEST_RND_HI32
and bpf_jit_harden=2, three runs of loading 131072 "ja 0":
base patched
pyperf180 0.512 s 0.350 s
pyperf600 1.407 s 0.885 s
strobemeta 0.591 s 0.588 s
test_verif_scale2 0.643 s 0.646 s
pyperf180, BPF_F_TEST_RND_HI32 1.708 s 0.360 s
pyperf600, BPF_F_TEST_RND_HI32 5.161 s 0.891 s
pyperf180, bpf_jit_harden=2 3.185 s 0.362 s
pyperf600, bpf_jit_harden=2 9.879 s 0.899 s
131072 "ja 0" removed 53.146 s 0.769 s
With bpf_jit_harden=2, test_verifier's "ld_dw: xor semi-random 64 bit
imms, test 5" doesn't load within 900 s on base and loads in 5 s with
the series.
For the 1052 objects of the selftests, every program that loads has the
same xlated code, line info and func info on both kernels, by default,
with BPF_F_TEST_RND_HI32 and with bpf_jit_harden=2, masking the
immediates that hold addresses, BTF ids and blinding constants.
test_verifier passes on both, test_bpf fails the same 53 tests on both
when hardened, and test_progs only shows failures that are flaky in
parallel runs.
[1] https://lore.kernel.org/bpf/a714ee96d0ad96bbc9d51037616e5c4e2790a8ec.camel@gmail.com/
[2] https://lore.kernel.org/bpf/1562275611-31790-1-git-send-email-jiong.wang@netronome.com/
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
---
V1 -> V2:
- Convert every pass and remove the old patching code (Alexei)
- Build the new image in core.c, so that blinding without a verifier env
uses the list too
- Let the list remove instructions, insert in front of one and patch one
twice
- Pick JEQ or gotol for a backward may_goto from its offset grown by the
patches in between, v1 picked JEQ when that offset was -32768 (CI bot)
- Test a backward may_goto expanded to gotol
- Test a jump that the patches push out of its 16-bit range, and a gotox
to a patched insn
- Rebase onto current bpf-next, which adds the arena_scalar rewrite
v1: https://lore.kernel.org/r/20261001-bpf-verifier-patch-batch-v1-0-a12df8a09160@gmail.com
---
Qiliang Yuan (22):
bpf: Add a list of deferred instruction patches
bpf: Remap the verifier state through the patch list
bpf: Apply single-instruction patches of the verifier in place
bpf: Queue the rewrites of bpf_do_misc_fixups()
bpf: Expand a backward may_goto to gotol when patches push it out of range
bpf: Drop the constant delta from bpf_do_misc_fixups()
bpf: Let the patch list remove instructions
bpf: Remove dead code through the patch list
bpf: Strip nops through the patch list
bpf: Batch the patches of bpf_opt_subreg_zext_lo32_rnd_hi32()
bpf: Allow patching an instruction twice through the patch list
bpf: Teach the patch list to insert in front of an instruction
bpf: Allow inserting in front of a queued patch
bpf: Move bpf_convert_ctx_accesses() to the patch list
bpf: Insert the may_goto counter setup through the patch list
bpf: Append the hidden subprog through the patch list
bpf: Inline bpf_loop() calls through the patch list
bpf: Apply the patch list without a verifier env
bpf: Blind constants through the patch list
bpf: Remove the old instruction patching code
selftests/bpf: Test jumps around patches of bpf_do_misc_fixups()
selftests/bpf: Cover a backward may_goto pushed out of range by patches
include/linux/bpf.h | 4 +-
include/linux/bpf_verifier.h | 87 +-
include/linux/filter.h | 16 -
kernel/bpf/bpf_insn_array.c | 35 +-
kernel/bpf/core.c | 552 ++++++---
kernel/bpf/fixups.c | 1285 +++++++++-----------
kernel/bpf/verifier.c | 46 +-
tools/testing/selftests/bpf/prog_tests/verifier.c | 2 +
.../selftests/bpf/progs/verifier_patch_list.c | 210 ++++
9 files changed, 1240 insertions(+), 997 deletions(-)
---
base-commit: 7101b10cf281f629ac58c99697ca6f6d082b99a7
change-id: 20261001-bpf-verifier-patch-batch-2442080e837d
Best regards,
--
Qiliang Yuan <odys.yuan@gmail.com>
next reply other threads:[~2026-10-30 11:51 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 11:51 Qiliang Yuan [this message]
2026-10-30 11:51 ` [PATCH bpf-next v2 01/22] bpf: Add a list of deferred instruction patches Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 02/22] bpf: Remap the verifier state through the patch list Qiliang Yuan
2026-10-30 12:44 ` bot+bpf-ci
2026-10-30 11:51 ` [PATCH bpf-next v2 03/22] bpf: Apply single-instruction patches of the verifier in place Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 04/22] bpf: Queue the rewrites of bpf_do_misc_fixups() Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 05/22] bpf: Expand a backward may_goto to gotol when patches push it out of range Qiliang Yuan
2026-10-30 12:59 ` bot+bpf-ci
2026-10-30 11:51 ` [PATCH bpf-next v2 06/22] bpf: Drop the constant delta from bpf_do_misc_fixups() Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 07/22] bpf: Let the patch list remove instructions Qiliang Yuan
2026-10-30 12:11 ` sashiko-bot
2026-10-30 11:51 ` [PATCH bpf-next v2 08/22] bpf: Remove dead code through the patch list Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 09/22] bpf: Strip nops " Qiliang Yuan
2026-10-30 12:45 ` bot+bpf-ci
2026-10-30 11:51 ` [PATCH bpf-next v2 10/22] bpf: Batch the patches of bpf_opt_subreg_zext_lo32_rnd_hi32() Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 11/22] bpf: Allow patching an instruction twice through the patch list Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 12/22] bpf: Teach the patch list to insert in front of an instruction Qiliang Yuan
2026-10-30 12:44 ` bot+bpf-ci
2026-10-30 11:51 ` [PATCH bpf-next v2 13/22] bpf: Allow inserting in front of a queued patch Qiliang Yuan
2026-10-30 11:51 ` [PATCH bpf-next v2 14/22] bpf: Move bpf_convert_ctx_accesses() to the patch list Qiliang Yuan
2026-10-30 12:24 ` sashiko-bot
2026-10-30 11:52 ` [PATCH bpf-next v2 15/22] bpf: Insert the may_goto counter setup through " Qiliang Yuan
2026-10-30 11:52 ` [PATCH bpf-next v2 16/22] bpf: Append the hidden subprog " Qiliang Yuan
2026-10-30 11:52 ` [PATCH bpf-next v2 17/22] bpf: Inline bpf_loop() calls " Qiliang Yuan
2026-10-30 11:52 ` [PATCH bpf-next v2 18/22] bpf: Apply the patch list without a verifier env Qiliang Yuan
2026-10-30 11:52 ` [PATCH bpf-next v2 19/22] bpf: Blind constants through the patch list Qiliang Yuan
2026-10-30 12:44 ` bot+bpf-ci
2026-10-30 11:52 ` [PATCH bpf-next v2 20/22] bpf: Remove the old instruction patching code Qiliang Yuan
2026-10-30 11:52 ` [PATCH bpf-next v2 21/22] selftests/bpf: Test jumps around patches of bpf_do_misc_fixups() Qiliang Yuan
2026-10-30 11:52 ` [PATCH bpf-next v2 22/22] selftests/bpf: Cover a backward may_goto pushed out of range by patches Qiliang Yuan
2026-10-30 12:13 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261030-bpf-verifier-patch-batch-v2-0-55cd43439f7c@gmail.com \
--to=odys.yuan@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox