All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Fastabend <john.fastabend@gmail.com>
To: Yonghong Song <yhs@fb.com>,
	John Fastabend <john.fastabend@gmail.com>,
	Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>, bpf <bpf@vger.kernel.org>,
	Alexei Starovoitov <ast@kernel.org>
Subject: Re: [bpf PATCH v3] bpf: verifier, do_refine_retval_range may clamp umin to 0 incorrectly
Date: Tue, 04 Feb 2020 19:05:23 -0800	[thread overview]
Message-ID: <5e3a30f3a9221_3b4f2ab2596925b8e3@john-XPS-13-9370.notmuch> (raw)
In-Reply-To: <fe3e8178-c069-4299-10df-8c983388c48c@fb.com>

Yonghong Song wrote:
> 
> 
> On 2/4/20 11:55 AM, John Fastabend wrote:
> > Alexei Starovoitov wrote:
> >> On Fri, Jan 31, 2020 at 9:16 AM John Fastabend <john.fastabend@gmail.com> wrote:
> >>>
> >>> Also don't mind to build pseudo instruction here for signed extension
> >>> but its not clear to me why we are getting different instruction
> >>> selections? Its not clear to me why sext is being chosen in your case?

[...]

> >> zext is there both cases and it will be optimized with your llvm patch.
> >> So please send it. Don't delay :)
> > 
> > LLVM patch here, https://urldefense.proofpoint.com/v2/url?u=https-3A__reviews.llvm.org_D73985&d=DwICaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=DA8e1B5r073vIqRrFz7MRA&m=VnK0SKxGnw_yzWjaO-cZFrmlZB9p86L4me-mWE_vDto&s=jwDJuAEdJ23HVcvIILvkfxvTNSe_cgHQFn_MpXssfXc&e=
> > 
> > With updated LLVM I can pass selftests with above fix and additional patch
> > below to get tighter bounds on 32bit registers. So going forward I think
> > we need to review and assuming it looks good commit above llvm patch and
> > then go forward with this series.
> 
> Thanks. The llvm patch looks sane, but after applying the patch, I hit 
> several selftest failures. For example, strobemeta_nounroll1.o.
> 
> The following is a brief analysis of the verifier state:
> 
> 184: 
> R0=inv(id=0,smax_value=9223372032559808513,umax_value=18446744069414584321,var_off=(0x0; 
> 0xffffffff00000001))
> R7=inv0
> 
> 184: (bc) w7 = w0
> 185: 
> R0=inv(id=0,smax_value=9223372032559808513,umax_value=18446744069414584321,var_off=(0x0; 
> 0xffffffff00000001))
> R7_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0x1))
> 
> 185: (67) r7 <<= 32
> 186: 
> R0=inv(id=0,smax_value=9223372032559808513,umax_value=18446744069414584321,var_off=(0x0; 
> 0xffffffff00000001))
> R7_w=inv(id=0,umax_value=4294967296,var_off=(0x0; 0x100000000))
> 
> 186: (77) r7 >>= 32
> 187: 
> R0=inv(id=0,smax_value=9223372032559808513,umax_value=18446744069414584321,var_off=(0x0; 
> 0xffffffff00000001))
> R7_w=inv(id=0,umax_value=1,var_off=(0x0; 0x1))
> 
> You can see after left and right shift, we got a better R7 umax_value=1.
> Without the left and right shift, eventually verifier complains.
> 
> Can we make uname_value=1 at insn 'w7 = w0'?
> Currently, we cannot do this due to the logic in coerce_reg_to_size().
> It looks correct to me to ignore the top mask as we know the upper 32bit 
> will be discarded.
> 
> I have implemented in my previous patch to deal with signed compares.
> The following is the patch to fix this particular issue:

[...]

> 
> With the above patch, there is still one more issue in test_seg6_loop.o, 
> which is related to llvm code generation, w.r.t. our strange 32bit 
> packet begin and packet end.
> 
> The following patch is generated:
> 
> 2: (61) r1 = *(u32 *)(r6 +76)
> 3: R1_w=pkt(id=0,off=0,r=0,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) 
> R6_w=ctx(id=0,off=0,imm=0) R10=fp0
> ; cursor = (void *)(long)skb->data;
> 3: (bc) w8 = w1
> 4: R1_w=pkt(id=0,off=0,r=0,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) 
> R6_w=ctx(id=0,off=0,imm=0) 
> R8_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R10=fp0
> ; if ((void *)ipver + sizeof(*ipver) > data_end)
> 4: (bf) r3 = r8
> 
> In the above r1 is packet pointer and after the assignment, it becomes a 
> scalar and will lead later verification failure.
> 
> Without the patch, we generates:
> 1: R1=ctx(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) R10=fp0
> ; data_end = (void *)(long)skb->data_end;
> 1: (61) r1 = *(u32 *)(r6 +80)
> 2: R1_w=pkt_end(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) R10=fp0
> ; cursor = (void *)(long)skb->data;
> 2: (61) r8 = *(u32 *)(r6 +76)
> 3: R1_w=pkt_end(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) 
> R8_w=pkt(id=0,off=0,r=0,imm=0) R10=fp0
> ; if ((void *)ipver + sizeof(*ipver) > data_end)
> 3: (bf) r2 = r8
> 4: R1_w=pkt_end(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) 
> R6_w=ctx(id=0,off=0,imm=0) R8_w=pkt(id=0,off=0,r=0,imm=0) R10=fp0
> 4: (07) r2 += 1
> 5: R1_w=pkt_end(id=0,off=0,imm=0) R2_w=pkt(id=0,off=1,r=0,imm=0) 
> R6_w=ctx(id=0,off=0,imm=0) R8_w=pkt(id=0,off=0,r=0,imm=0) R10=fp0
> 
> r2 keeps as a packet pointer, so we don't have issues later.
> 
> Not sure how we could fix this in llvm as llvm does not really have idea
> the above w1 in w8 = w1 is a packet pointer.
> 

OK thanks for analysis. I have this on my stack as well but need to
check its correct still,

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 320e2df..3072dba7 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2804,8 +2804,11 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size)
                reg->umax_value = mask;
        }
        reg->smin_value = reg->umin_value;
-       if (reg->smax_value < 0 || reg->smax_value > reg->umax_value)
+       if (reg->smax_value < 0 || reg->smax_value > reg->umax_value) {
                reg->smax_value = reg->umax_value;
+       } else {
+               reg->umax_value = reg->smax_value;
+       }
 }

this helps but still hitting above issue with the packet pointer as
you pointed out. I'll sort out how we can fix this. Somewhat related
we have a similar issue we hit fairly consistently I've been meaning
to sort out where the cmp happens on a different register then is
used in the call, for example something like this pseudocode

   r8 = r2
   if r8 > blah goto +label
   r1 = dest_ptr
   r1 += r2
   r2 = size
   r3 = ptr
   call #some_call

and the verifier aborts because r8 was verified instead of r2. The
working plan was to walk back in the def-use chain and sort it out
but tbd.

.John
   

  reply	other threads:[~2020-02-05  3:05 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-27 19:29 [bpf PATCH v3] bpf: verifier, do_refine_retval_range may clamp umin to 0 incorrectly John Fastabend
2020-01-29 16:25 ` Daniel Borkmann
2020-01-29 19:28   ` Alexei Starovoitov
2020-01-29 22:20     ` Daniel Borkmann
2020-01-29 22:52       ` John Fastabend
2020-01-30  0:04         ` Alexei Starovoitov
2020-01-30 17:38           ` John Fastabend
2020-01-30 17:59             ` Alexei Starovoitov
2020-01-30 23:34               ` John Fastabend
2020-01-31  0:15                 ` Yonghong Song
2020-01-31  0:44                   ` John Fastabend
2020-01-31  0:52                     ` Yonghong Song
2020-01-31  2:50                     ` Alexei Starovoitov
2020-01-31  0:28                 ` Yonghong Song
2020-01-31  0:48                   ` John Fastabend
2020-01-31  2:46                 ` Alexei Starovoitov
2020-01-31  5:48                   ` John Fastabend
2020-01-31  6:18                     ` Alexei Starovoitov
2020-01-31 17:16                       ` John Fastabend
2020-01-31 21:36                         ` Alexei Starovoitov
2020-02-04 19:55                           ` John Fastabend
2020-02-05  1:21                             ` Yonghong Song
2020-02-05  3:05                               ` John Fastabend [this message]
2020-02-06  1:24                                 ` Yonghong Song
2020-02-07 20:47                                   ` John Fastabend
2020-02-08  6:23                                     ` Yonghong Song
2020-04-09 15:03 ` Lorenzo Fontana

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=5e3a30f3a9221_3b4f2ab2596925b8e3@john-XPS-13-9370.notmuch \
    --to=john.fastabend@gmail.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=yhs@fb.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.