All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yonghong.song@linux.dev>
To: Menglong Dong <menglong8.dong@gmail.com>
Cc: andrii@kernel.org, ast@kernel.org, daniel@iogearbox.net,
	john.fastabend@gmail.com, martin.lau@linux.dev, song@kernel.org,
	kpsingh@kernel.org, sdf@google.com, haoluo@google.com,
	jolsa@kernel.org, bpf@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH bpf-next] bpf: make the verifier trace the "not qeual" for regs
Date: Mon, 11 Dec 2023 07:03:49 -0800	[thread overview]
Message-ID: <96228ae1-a199-4f9a-8d40-d161a718c3c9@linux.dev> (raw)
In-Reply-To: <CADxym3bNJXWZRfcGWpD7YW1rFe93vSOastmGrLvAcG3U2SaUdg@mail.gmail.com>


On 12/11/23 1:39 AM, Menglong Dong wrote:
> Hello,
>
> On Mon, Dec 11, 2023 at 1:09 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>>
>> On 12/10/23 5:00 AM, Menglong Dong wrote:
>>> We can derive some new information for BPF_JNE in regs_refine_cond_op().
>>> Take following code for example:
>>>
>>>     /* The type of "a" is u16 */
>>>     if (a > 0 && a < 100) {
>>>       /* the range of the register for a is [0, 99], not [1, 99],
>>>        * and will cause the following error:
>>>        *
>>>        *   invalid zero-sized read
>>>        *
>>>        * as a can be 0.
>>>        */
>>>       bpf_skb_store_bytes(skb, xx, xx, a, 0);
>>>     }
>> Could you have a C test to demonstrate this example?
>> Also, you should have a set of inline asm code (progs/verifier*.c)
>> to test various cases as in mark_reg32_not_equal() and
>> mark_reg_not_equal().
>>
> Yeah! I found that this part is tested in the test_progs/reg_bounds_crafted
> too, and this commit failed that test case, which I should fix in the next
> version.
>
>>> In the code above, "a > 0" will be compiled to "jmp xxx if a == 0". In the
>>> TRUE branch, the dst_reg will be marked as known to 0. However, in the
>>> fallthrough(FALSE) branch, the dst_reg will not be handled, which makes
>>> the [min, max] for a is [0, 99], not [1, 99].
>>>
>>> For BPF_JNE, we can reduce the range of the dst reg if the src reg is a
>>> const and is exactly the edge of the dst reg.
>>>
>>> Signed-off-by: Menglong Dong <menglong8.dong@gmail.com>
>>> ---
>>>    kernel/bpf/verifier.c | 45 ++++++++++++++++++++++++++++++++++++++++++-
>>>    1 file changed, 44 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>>> index 727a59e4a647..7b074ac93190 100644
>>> --- a/kernel/bpf/verifier.c
>>> +++ b/kernel/bpf/verifier.c
>>> @@ -1764,6 +1764,40 @@ static void __mark_reg_const_zero(struct bpf_reg_state *reg)
>>>        reg->type = SCALAR_VALUE;
>>>    }
>>>
>>> +#define CHECK_REG_MIN(value)                 \
>>> +do {                                         \
>>> +     if ((value) == (typeof(value))imm)      \
>>> +             value++;                        \
>>> +} while (0)
>>> +
>>> +#define CHECK_REG_MAX(value)                 \
>>> +do {                                         \
>>> +     if ((value) == (typeof(value))imm)      \
>>> +             value--;                        \
>>> +} while (0)
>>> +
>>> +static void mark_reg32_not_equal(struct bpf_reg_state *reg, u64 imm)
>>> +{
>> What if reg->s32_min_value == imm and reg->s32_max_value == imm?
>> Has this been handled in previous verifier logic?
> Will such a case happen? In current code path, the src reg is a const,
> and the is_branch_taken() will return 0 or 1 if the
> dst_reg->s32_min_value == dst_reg->s32_max_value.
>
> Enn......maybe we can do more checking here in case that someone
> calls this function in another place.

I double checked the source code as well. Indeed, 'reg' should
not be a constant as it has been handled in is_branch_taken()
properly. Ignore my comments above then. Thanks!

>
> Thanks!
> Menglong Dong
>
>>> +             CHECK_REG_MIN(reg->s32_min_value);
>>> +             CHECK_REG_MAX(reg->s32_max_value);
>>> +             CHECK_REG_MIN(reg->u32_min_value);
>>> +             CHECK_REG_MAX(reg->u32_max_value);
>>> +}
>>> +
>>> +static void mark_reg_not_equal(struct bpf_reg_state *reg, u64 imm)
>>> +{
>>> +             CHECK_REG_MIN(reg->smin_value);
>>> +             CHECK_REG_MAX(reg->smax_value);
>>> +
>>> +             CHECK_REG_MIN(reg->umin_value);
>>> +             CHECK_REG_MAX(reg->umax_value);
>>> +
>>> +             CHECK_REG_MIN(reg->s32_min_value);
>>> +             CHECK_REG_MAX(reg->s32_max_value);
>>> +             CHECK_REG_MIN(reg->u32_min_value);
>>> +             CHECK_REG_MAX(reg->u32_max_value);
>>> +}
>>> +
>>>    static void mark_reg_known_zero(struct bpf_verifier_env *env,
>>>                                struct bpf_reg_state *regs, u32 regno)
>>>    {
>>> @@ -14332,7 +14366,16 @@ static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state
>>>                }
>>>                break;
>>>        case BPF_JNE:
>>> -             /* we don't derive any new information for inequality yet */
>>> +             /* try to recompute the bound of reg1 if reg2 is a const and
>>> +              * is exactly the edge of reg1.
>>> +              */
>>> +             if (is_reg_const(reg2, is_jmp32)) {
>>> +                     val = reg_const_value(reg2, is_jmp32);
>>> +                     if (is_jmp32)
>>> +                             mark_reg32_not_equal(reg1, val);
>>> +                     else
>>> +                             mark_reg_not_equal(reg1, val);
>>> +             }
>>>                break;
>>>        case BPF_JSET:
>>>                if (!is_reg_const(reg2, is_jmp32))

  reply	other threads:[~2023-12-11 15:04 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-10 13:00 [PATCH bpf-next] bpf: make the verifier trace the "not qeual" for regs Menglong Dong
2023-12-11  5:09 ` Yonghong Song
2023-12-11  9:39   ` Menglong Dong
2023-12-11 15:03     ` Yonghong Song [this message]
2023-12-11 19:15 ` Andrii Nakryiko
2023-12-12  2:15   ` Menglong Dong
2023-12-12  3:51     ` 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=96228ae1-a199-4f9a-8d40-d161a718c3c9@linux.dev \
    --to=yonghong.song@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=haoluo@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=menglong8.dong@gmail.com \
    --cc=sdf@google.com \
    --cc=song@kernel.org \
    /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.