BPF List
 help / color / mirror / Atom feed
From: Alexei Starovoitov <alexei.starovoitov@gmail.com>
To: Eduard Zingerman <eddyz87@gmail.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>,
	Andrew Werner <awerner32@gmail.com>, bpf <bpf@vger.kernel.org>,
	Andrei Matei <andreimatei1@gmail.com>,
	Tamir Duberstein <tamird@gmail.com>,
	Joanne Koong <joannelkoong@gmail.com>,
	kernel-team@dataexmachina.dev, Song Liu <song@kernel.org>,
	Kumar Kartikeya Dwivedi <memxor@gmail.com>
Subject: Re: [BUG] verifier escape with iteration helpers (bpf_loop, ...)
Date: Tue, 3 Oct 2023 16:08:20 -0700	[thread overview]
Message-ID: <20231003230820.iazvofhysfmurwon@MacBook-Pro-49.local> (raw)
In-Reply-To: <5b7f4b6199decf266a9218b674c232662ed13db5.camel@gmail.com>

On Wed, Oct 04, 2023 at 12:52:07AM +0300, Eduard Zingerman wrote:
> On Tue, 2023-10-03 at 11:50 -0700, Alexei Starovoitov wrote:
> > On Tue, Oct 3, 2023 at 8:33 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> > > 
> > > When I put states to the loop stack I do copy_verifier_state() and
> > > increase .branches counter for each state parent, so this should not
> > > trigger warnings with update_branch_counts().
> > 
> > No warn doesn't mean it's correct.
> > I suspect what your reschedule_loop_states() will increase
> > branches from 0 to 1.
> > Which is equivalent to increasing refcnt from zero. Not good.
> 
> Not really, here is how I modified bpf_verifier_env:
> 
>     struct bpf_verifier_state_stack {
>         struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */
>         int size;                             /* number of states to be processed */
>     };
>     
>     struct bpf_verifier_env {
>         ...
>         struct bpf_verifier_state_stack stack;
>         struct bpf_verifier_state_stack loop_stack;
>         ...
>     }
> 
> Here env->stack is used for DFS traversal and env->loop_stack is used
> to delay verification of the loop states.
> 
> When bpf_iter_next() is reached in state C and states_equal() shows
> that there is potentially equivalent state V:
> - copy C' of C is created sing copy_verifier_state(), it updates all
>   branch counters up the ownership chain as with any other state;
> - C' is put to env->loop_stack.

and C' points to normal parent and increments its branches as part of __push_stack().

By delaying all looping states that looks to be equal to V states
due to broken precision marks the verifier will walk almost everything
after the loop, converge all branches to 0, then clean_live_states() and REG_LIVE_DONE
in the bottom part,
then it will proceed to verify all branches before the loop, but
since their branch counter is stuck due to states in loop_stack,
the upper part of the program won't get the same treatment.
update_branch_counts() will never go past the point where C' was put on loop_stack,
so every state before the loop will have branches > 0 and
verification of branches before the loop will not do any state pruning at all.

void foo()
{
  if (...) { .. } // no pruning
  if (...) { .. } // no pruning

  bpf_for(...)
  if (...) { .. } // all ok
}

Essentially any complex code before the loop has a high chance of the verifier
state explosion.

> It is possible and correct to propagate liveness and precision from V
> to C when loop steady state is achieved, as at that point we know for
> sure that C is a sub-state of V. However, currently loop states are
> tracked globally and no states are processed after loops steady state
> is reached, hence I don't do liveness and precision propagation.

Hmm. I think the code is doing it:
if (is_iter_next_insn(env, insn_idx)) {
  if (states_equal(env, &sl->state, cur)) {
    push_loop_stack(env, insn_idx, env->prev_insn_idx);
    goto hit;
hit:
  propagate_liveness()

> The necessity to visit all grandchildren states of V leads to
> necessity of mixed DFS and BFS traversal of the loop states.

DFS + BFS traversal doesn't guarantee safety.
We delayed looping states in loop_stack, but it doesn't mean
that the loop body reached a steady state.
Your own num_iter_bug() is an example.
The verifier will miss exploring path with r7 = 0xdead.
When C' is popped from loop_stack there is chance it will explore them,
but there is no guarantee.
For this particular num_iter_bug() case the loop processing
will eventually propagate precision marks and retrying with C' later,
the C' will be correctly rejected, since precision marks are there.
But I think that is more due to luck and the shape of the test.

if (is_iter_next_insn(env, insn_idx)) {
  if (states_equal(env, &sl->state, cur)) {

is a foot gun. It finds broken equivalence and potentially skipping
whole blocks of code.
What guarantees that C' from loop_stack will explore them?
I think avoiding states_equal(V, cur) when V state didn't converge
is a mandatory part of the fix.

I can see that little bit of out-of-order state processing probably
is still correct, but delaying loop_stack all the way until 
env->stack.size == 0 is just broken.
For example we can push looping state in process_iter_next_call()
not the top of the stack, but place it after branches with
insn_idx >= iter_next's insn_idx.
This way the delayed looping states will still be processed
around loop processing and every code block before the loop
will converge to branches = 0.
To do that we don't need another loop_stack.

I think we need a call to converge. Office hours on Thu at 9am?
Or tomorrow at 9am?

  parent reply	other threads:[~2023-10-03 23:08 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-07 14:04 [BUG] verifier escape with iteration helpers (bpf_loop, ...) Andrew Werner
2023-07-07 16:44 ` Alexei Starovoitov
2023-07-07 18:08   ` Andrii Nakryiko
2023-07-07 18:21     ` Andrew Werner
2023-09-17 21:37     ` Eduard Zingerman
2023-09-17 22:09       ` Kumar Kartikeya Dwivedi
2023-09-18 13:06         ` Eduard Zingerman
2023-09-19 16:28           ` Eduard Zingerman
2023-09-19 23:02             ` Andrii Nakryiko
2023-09-20  0:19               ` Eduard Zingerman
2023-09-20 16:20                 ` Eduard Zingerman
2023-09-20 16:57                   ` Andrii Nakryiko
2023-09-21  9:14                 ` Alexei Starovoitov
2023-09-21 11:03                   ` Eduard Zingerman
2023-09-21 12:56                     ` Alexei Starovoitov
2023-09-21 16:23                       ` Eduard Zingerman
2023-09-21 16:35                         ` Andrii Nakryiko
2023-09-21 18:16                           ` Eduard Zingerman
2023-09-22  1:01                             ` Eduard Zingerman
2023-09-22  2:48                               ` Andrii Nakryiko
2023-09-22 18:36                                 ` Eduard Zingerman
2023-09-22 20:52                                   ` Andrii Nakryiko
2023-09-25  1:01                                     ` Eduard Zingerman
2023-09-26  0:33                                       ` Andrii Nakryiko
2023-09-26 15:55                                         ` Eduard Zingerman
2023-09-26 16:25                                           ` Andrii Nakryiko
2023-09-28  1:09                                             ` Eduard Zingerman
2023-09-28 18:30                                               ` Andrii Nakryiko
2023-10-02  3:26                                                 ` Eduard Zingerman
2023-09-30  0:41                                               ` Alexei Starovoitov
2023-10-02  1:40                                                 ` Eduard Zingerman
2023-10-02 16:29                                                   ` Alexei Starovoitov
2023-10-02 17:18                                                     ` Eduard Zingerman
2023-10-03  0:05                                                       ` Alexei Starovoitov
2023-10-03  2:00                                                         ` Alexei Starovoitov
2023-10-03 15:33                                                         ` Eduard Zingerman
2023-10-03 16:07                                                           ` Alexei Starovoitov
2023-10-03 18:50                                                           ` Alexei Starovoitov
2023-10-03 21:52                                                             ` Eduard Zingerman
2023-10-03 22:03                                                               ` Eduard Zingerman
2023-10-03 23:08                                                               ` Alexei Starovoitov [this message]
2023-10-03 23:14                                                                 ` Eduard Zingerman
2023-10-04  0:22                                                                   ` Andrii Nakryiko
2023-10-04  1:05                                                                 ` Eduard Zingerman
2023-10-04  2:57                                                                   ` Alexei Starovoitov
2023-10-04  5:50                                                                     ` Alexei Starovoitov
2023-10-04  9:49                                                                       ` Eduard Zingerman
2023-10-04 11:52                                                                     ` Eduard Zingerman
2023-09-19 23:14       ` Andrii Nakryiko
2023-09-20  0:06         ` Eduard Zingerman
2023-09-20 16:37           ` Andrii Nakryiko
2023-09-20 17:13             ` Eduard Zingerman

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=20231003230820.iazvofhysfmurwon@MacBook-Pro-49.local \
    --to=alexei.starovoitov@gmail.com \
    --cc=andreimatei1@gmail.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=awerner32@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=eddyz87@gmail.com \
    --cc=joannelkoong@gmail.com \
    --cc=kernel-team@dataexmachina.dev \
    --cc=memxor@gmail.com \
    --cc=song@kernel.org \
    --cc=tamird@gmail.com \
    /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