From: Eduard Zingerman <eddyz87@gmail.com>
To: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: bpf <bpf@vger.kernel.org>, Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Martin KaFai Lau <martin.lau@linux.dev>,
Kernel Team <kernel-team@fb.com>,
Yonghong Song <yonghong.song@linux.dev>
Subject: Re: [PATCH bpf-next v1 1/2] bpf: force checkpoint when jmp history is too long
Date: Tue, 22 Oct 2024 19:52:35 -0700 [thread overview]
Message-ID: <a9bd25331dbfdd5a968f9c4320608d2949176fc1.camel@gmail.com> (raw)
In-Reply-To: <658394292b21edb9b30a5add27a8cd7fa8a778ed.camel@gmail.com>
On Mon, 2024-10-21 at 22:38 -0700, Eduard Zingerman wrote:
[...]
> This takes ~10 minutes to verify on master.
> Surprisingly current patch does not seem to help,
> I'll investigate this tomorrow.
> Full example is in the end of the email.
I messed up the example a little bit.
The example shared previously takes so long to process because of "goto +0;".
opt_remove_nops() deletes such jumps and we know that bpf_remove_insns()
is not efficient.
Corrected example uses conditional jump in place of "goto +0;" and
slightly adjusted counters. Full program is here:
https://gist.github.com/eddyz87/cb813387323b78bcd6a7e264fc44c817
Here is it's verification log to get the idea:
0: (79) r2 = *(u64 *)(r1 +0)
1: (b7) r0 = 0
2: (35) if r2 >= 0x1 goto pc+5
push_stack: at 2, jmp_history_cnt 0
3: (35) if r0 >= 0x0 goto pc+0
4: (35) if r0 >= 0x0 goto pc+0
5: (35) if r0 >= 0x0 goto pc+0
6: (35) if r0 >= 0x0 goto pc+0
is_state_visited: new checkpoint at 7, resetting env->jmps_processed
7: (95) exit
8: (35) if r2 >= 0x2 goto pc+7
push_stack: at 8, jmp_history_cnt 1
9: (35) if r0 >= 0x0 goto pc+0
10: (35) if r0 >= 0x0 goto pc+0
11: (35) if r0 >= 0x0 goto pc+0
12: (35) if r0 >= 0x0 goto pc+0
13: (35) if r0 >= 0x0 goto pc+0
14: (35) if r0 >= 0x0 goto pc+0
is_state_visited: new checkpoint at 15, resetting env->jmps_processed
15: (95) exit
...
320: (35) if r2 >= 0x29 goto pc+7
push_stack: at 320, jmp_history_cnt 40
320: R2_w=40
321: (35) if r0 >= 0x0 goto pc+0
322: (35) if r0 >= 0x0 goto pc+0
323: (35) if r0 >= 0x0 goto pc+0
324: (35) if r0 >= 0x0 goto pc+0
325: (35) if r0 >= 0x0 goto pc+0
326: (35) if r0 >= 0x0 goto pc+0
is_state_visited: new checkpoint at 327, resetting env->jmps_processed
327: (95) exit
...
A bpf program w/o loops, at each 'if r2 >= ...' push_stack() saves a
state with ever increasing jump history.
- right amount of 'if r0 >= ...' instructions is maintained before 'exit'
to force a new checkpoint;
- exit is processed;
- state is popped from the stack and first insn it processes is
'if r2 >= ...', thus a new state is saved by push_stack()
with jump history longer by 1.
On master this fails with ENOMEM and the following error in the log:
[ 418.083600] test_progs: page allocation failure: order:7, mode:0x140cc0(GFP_USER|__GFP_COMP), \
nodemask=(null),cpuset=/,mems_allowed=0
...
[ 418.084158] Call Trace:
...
[ 418.084649] krealloc_noprof+0x53/0xd0
[ 418.084688] copy_verifier_state+0x78/0x390
...
Same happens if jmp_history_cnt check is moved to 'skip_inf_loop_check':
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18022,7 +18022,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
* at the end of the loop are likely to be useful in pruning.
*/
skip_inf_loop_check:
- if (!force_new_state &&
+ if (!force_new_state && cur->jmp_history_cnt < 40 &&
env->jmps_processed - env->prev_jmps_processed < 20 &&
env->insn_processed - env->prev_insn_processed < 100)
Or if it is in the else branch. Simply because 'skip_inf_loop_check' is
for instructions that have been already seen on the current verification path.
However, with change suggested in this patch-set such ENOMEM situation
is not possible. Hence I insist that large enough jmp_history_cnt
should force a new state, and point where I put the check covers more
cases then alternatives.
next prev parent reply other threads:[~2024-10-23 2:52 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-18 2:03 [PATCH bpf-next v1 1/2] bpf: force checkpoint when jmp history is too long Eduard Zingerman
2024-10-18 2:03 ` [PATCH bpf-next v1 2/2] selftests/bpf: test with a very short loop Eduard Zingerman
2024-10-18 11:05 ` Daniel Borkmann
2024-10-18 11:03 ` [PATCH bpf-next v1 1/2] bpf: force checkpoint when jmp history is too long Daniel Borkmann
2024-10-18 16:47 ` Eduard Zingerman
2024-10-21 7:53 ` Daniel Borkmann
2024-10-21 20:23 ` Andrii Nakryiko
2024-10-22 2:03 ` Alexei Starovoitov
2024-10-22 3:19 ` Andrii Nakryiko
2024-10-22 2:18 ` Alexei Starovoitov
2024-10-22 2:27 ` Eduard Zingerman
2024-10-22 2:53 ` Alexei Starovoitov
2024-10-22 5:38 ` Eduard Zingerman
2024-10-23 2:52 ` Eduard Zingerman [this message]
2024-10-23 17:31 ` Andrii Nakryiko
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=a9bd25331dbfdd5a968f9c4320608d2949176fc1.camel@gmail.com \
--to=eddyz87@gmail.com \
--cc=alexei.starovoitov@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=martin.lau@linux.dev \
--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