BPF List
 help / color / mirror / Atom feed
From: Alexei Starovoitov <ast@meta.com>
To: Eduard Zingerman <eddyz87@gmail.com>,
	"Jose E. Marchesi" <jose.marchesi@oracle.com>,
	Yonghong Song <yhs@meta.com>,
	Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>,
	bpf@vger.kernel.org, ast@kernel.org, andrii@kernel.org,
	daniel@iogearbox.net, kernel-team@fb.com, yhs@fb.com,
	david.faust@oracle.com,
	James Hilliard <james.hilliard1@gmail.com>
Subject: Re: [RFC bpf-next 0/5] Support for BPF_ST instruction in LLVM C compiler
Date: Wed, 25 Jan 2023 21:49:21 -0800	[thread overview]
Message-ID: <58f2f815-e7d8-8205-4669-ed2254d813d1@meta.com> (raw)
In-Reply-To: <f1e4282bf00aa21a72fc5906f8c3be1ae6c94a5e.camel@gmail.com>

On 1/13/23 8:47 AM, Eduard Zingerman wrote:
>>>>         So the patch extends this logic to also handle BPF_ST.
>>>> The patch 3 is necessary to land before llvm starts generating 'st'
>>>> for ctx access.
>>>> That's clear, but I'm missing why patch 1 is necessary.
>>>> Sure, it's making the verifier understand scalar spills with 'st' and
>>>> makes 'st' equivalent to 'stx', but I'm missing why it's necessary.
>>>> What kind of programs fail to be verified when llvm starts generating 'st' ?
> 
> I should have added an example to the summary. There are a few
> test_prog tests that fail w/o this patch, namely atomic_bounds,
> dynptr, for_each, xdp_noinline, xdp_synproxy.
> 
> Here is how atomic_bounds looks:
> 
>    SEC("fentry/bpf_fentry_test1")
>    int BPF_PROG(sub, int x)
>    {
>            int a = 0;
>            int b = __sync_fetch_and_add(&a, 1);
>            /* b is certainly 0 here. Can the verifier tell? */
>            while (b)
>                    continue;
>            return 0;
>    }
> 
>      Compiled w/o BPF_ST                  Compiled with BPF_ST
>    
>    <sub>:                               <sub>:
>      w1 = 0x0
>      *(u32 *)(r10 - 0x4) = r1             *(u32 *)(r10 - 0x4) = 0x0
>      w1 = 0x1                             w1 = 0x1
>      lock *(u32 *)(r10 - 0x4) += r1       lock *(u32 *)(r10 - 0x4) += r1
>      if w1 == 0x0 goto +0x1 <LBB0_2>      if w1 == 0x0 goto +0x1 <LBB0_2>
>    
>    <LBB0_1>:                            <LBB0_1>:
>      goto -0x1 <LBB0_1>                   goto -0x1 <LBB0_1>
>    
>    <LBB0_2>:                            <LBB0_2>:
>      w0 = 0x0                             w0 = 0x0
>      exit                                 exit
> 
> When compiled with BPF_ST and verified w/o the patch #1 verification log
> looks as follows:
> 
>    0: R1=ctx(off=0,imm=0) R10=fp0
>    0: (62) *(u32 *)(r10 -4) = 0          ; R10=fp0 fp-8=mmmm????
>    1: (b4) w1 = 1                        ; R1_w=1
>    2: (c3) r1 = atomic_fetch_add((u32 *)(r10 -4), r1)    ; R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) R10=fp0 fp-8=mmmm????
>    3: (16) if w1 == 0x0 goto pc+1        ; R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
>    4: (05) goto pc-1
>    4: (05) goto pc-1
>    4: (05) goto pc-1
>    4: (05) goto pc-1
>    infinite loop detected at insn 4
> 
> When compiled w/o BPF_ST and verified w/o the patch #1 verification log
> looks as follows:
> 
>    func#0 @0
>    reg type unsupported for arg#0 function sub#5
>    0: R1=ctx(off=0,imm=0) R10=fp0
>    0: (b4) w1 = 0                        ; R1_w=0
>    1: (63) *(u32 *)(r10 -4) = r1
>    last_idx 1 first_idx 0
>    regs=2 stack=0 before 0: (b4) w1 = 0
>    2: R1_w=0 R10=fp0 fp-8=0000????
>    2: (b4) w1 = 1                        ; R1_w=1
>    ; int b = __sync_fetch_and_add(&a, 1);
>    3: (c3) r1 = atomic_fetch_add((u32 *)(r10 -4), r1)    ; R1_w=P0 R10=fp0 fp-8=mmmm????
>    4: (16) if w1 == 0x0 goto pc+1
>    6: R1_w=P0
>    6: (b4) w0 = 0                        ; R0_w=0
>    7: (95) exit
>    processed 7 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
> 
> The difference comes from the way zero write to `r10-4` is processed,
> with BPF_ST it is tracked as `fp-8=mmmm????` after write, without BPF_ST
> it is tracked as `fp-8=0000???? after` write.
> 
> Which is caused by the way `check_stack_write_fixed_off()` is written.
> For the register spills it either saves the complete register state or
> STACK_ZERO if register is known to be zero. However, for the BPF_ST it
> just saves STACK_MISC. Hence, the patch #1.

Thank you for explaining.
Though llvm changes are not ready, let's land the required
kernel changes now.
Please craft asm test cases for the issues you've seen with BPF_ST.

  reply	other threads:[~2023-01-26  5:49 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-31 16:31 [RFC bpf-next 0/5] Support for BPF_ST instruction in LLVM C compiler Eduard Zingerman
2022-12-31 16:31 ` [RFC bpf-next 1/5] bpf: more precise stack write reasoning for BPF_ST instruction Eduard Zingerman
2022-12-31 16:31 ` [RFC bpf-next 2/5] selftests/bpf: check if verifier tracks constants spilled by BPF_ST_MEM Eduard Zingerman
2022-12-31 16:31 ` [RFC bpf-next 3/5] bpf: allow ctx writes using BPF_ST_MEM instruction Eduard Zingerman
2022-12-31 16:31 ` [RFC bpf-next 4/5] selftests/bpf: test if pointer type is tracked for BPF_ST_MEM Eduard Zingerman
2022-12-31 16:31 ` [RFC bpf-next 5/5] selftests/bpf: don't match exact insn index in expected error message Eduard Zingerman
2023-01-04 22:10 ` [RFC bpf-next 0/5] Support for BPF_ST instruction in LLVM C compiler Andrii Nakryiko
2023-01-05 10:06   ` Jose E. Marchesi
2023-01-05 12:07     ` Eduard Zingerman
2023-01-05 15:07       ` Jose E. Marchesi
2023-01-12 22:27       ` Alexei Starovoitov
2023-01-13  8:02         ` Yonghong Song
2023-01-13  8:53           ` Jose E. Marchesi
2023-01-13 16:47             ` Eduard Zingerman
2023-01-26  5:49               ` Alexei Starovoitov [this message]
2023-01-13 19:23             ` Yonghong Song

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=58f2f815-e7d8-8205-4669-ed2254d813d1@meta.com \
    --to=ast@meta.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=david.faust@oracle.com \
    --cc=eddyz87@gmail.com \
    --cc=james.hilliard1@gmail.com \
    --cc=jose.marchesi@oracle.com \
    --cc=kernel-team@fb.com \
    --cc=yhs@fb.com \
    --cc=yhs@meta.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