From: Edward Cree <ecree.xilinx@gmail.com>
To: Shung-Hsi Yu <shung-hsi.yu@suse.com>,
Xu Kuohai <xukuohai@huaweicloud.com>,
bpf@vger.kernel.org
Cc: Eduard Zingerman <eddyz87@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
John Fastabend <john.fastabend@gmail.com>,
Andrii Nakryiko <andrii@kernel.org>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
KP Singh <kpsingh@kernel.org>,
Stanislav Fomichev <sdf@fomichev.me>, Hao Luo <haoluo@google.com>,
Jiri Olsa <jolsa@kernel.org>,
Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com>,
Santosh Nagarakatte <santosh.nagarakatte@rutgers.edu>,
Srinivas Narayana <srinivas.narayana@rutgers.edu>,
Matan Shachnai <m.shachnai@rutgers.edu>
Subject: Re: [RFC bpf-next v1] bpf, verifier: improve signed ranges inference for BPF_AND
Date: Tue, 30 Jul 2024 12:50:48 +0100 [thread overview]
Message-ID: <9505522b-de45-cf52-162b-76a3a52a6efe@gmail.com> (raw)
In-Reply-To: <20240719081702.137173-1-shung-hsi.yu@suse.com>
On 19/07/2024 09:17, Shung-Hsi Yu wrote:
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 8da132a1ef28..f6827f9e2076 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -13466,6 +13466,40 @@ static void scalar_min_max_mul(struct bpf_reg_state *dst_reg,
> }
> }
>
> +/* Clears all trailing bits after the most significant unset bit.
> + *
> + * Used for estimating the minimum possible value after BPF_AND. This
> + * effectively rounds a negative value down to a negative power-of-2 value
> + * (except for -1, which just return -1) and returning 0 for non-negative
> + * values. E.g. negative32_bit_floor(0xff0ff0ff) == 0xff000000.
> + */
> +static inline s32 negative32_bit_floor(s32 v)
> +{
> + u8 bits = fls(~v); /* find most-significant unset bit */
> + u32 delta;
> +
> + /* special case, needed because 1UL << 32 is undefined */
> + if (bits > 31)
> + return 0;
If I'm understanding correctly: this case happens when the input
is nonnegative: v >= 0 means ~v's msb is set, so fls(~v) = 32.
Might be worth calling that out in the comment.
> +
> + delta = (1UL << bits) - 1;
> + return ~delta;
> +}
> +
> +/* Same as negative32_bit_floor() above, but for 64-bit signed value */
> +static inline s64 negative_bit_floor(s64 v)
> +{
> + u8 bits = fls64(~v); /* find most-significant unset bit */
> + u64 delta;
> +
> + /* special case, needed because 1ULL << 64 is undefined */
> + if (bits > 63)
> + return 0;
> +
> + delta = (1ULL << bits) - 1;
> + return ~delta;
> +}
> +
> static void scalar32_min_max_and(struct bpf_reg_state *dst_reg,
> struct bpf_reg_state *src_reg)
> {
> @@ -13485,16 +13519,10 @@ static void scalar32_min_max_and(struct bpf_reg_state *dst_reg,
> dst_reg->u32_min_value = var32_off.value;
> dst_reg->u32_max_value = min(dst_reg->u32_max_value, umax_val);
>
> - /* Safe to set s32 bounds by casting u32 result into s32 when u32
> - * doesn't cross sign boundary. Otherwise set s32 bounds to unbounded.
> - */
> - if ((s32)dst_reg->u32_min_value <= (s32)dst_reg->u32_max_value) {
> - dst_reg->s32_min_value = dst_reg->u32_min_value;
> - dst_reg->s32_max_value = dst_reg->u32_max_value;
> - } else {
> - dst_reg->s32_min_value = S32_MIN;
> - dst_reg->s32_max_value = S32_MAX;
> - }
> + /* Handle the [-1, 0] & -CONSTANT case that's difficult for tnum */
> + dst_reg->s32_min_value = negative32_bit_floor(min(dst_reg->s32_min_value,
> + src_reg->s32_min_value));
> + dst_reg->s32_max_value = max(dst_reg->s32_max_value, src_reg->s32_max_value);
Either comment or commit message could maybe point out that the
work the deleted code was doing (propagating u32 bounds into
s32) is done by the caller later via __reg_deduce_bounds().
It's a bit of a shame that we can't get the sharp bound
[-13, 0] in your example, for which we technically have the
information we need — src_reg being constant means its tnum
carries information that negative_bit_floor(smin_value) is
throwing away — but I don't see an efficient way to handle
the case (it happens basically because only one operand
crosses the sign boundary, so the other operand's tnum is
informative) without going down the range-splitting road you
(I think rightly) discarded as unnecessarily complex.
Apart from that this all LGTM, so:
Reviewed-by: Edward Cree <ecree.xilinx@gmail.com>
prev parent reply other threads:[~2024-07-30 11:50 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-19 8:17 [RFC bpf-next v1] bpf, verifier: improve signed ranges inference for BPF_AND Shung-Hsi Yu
2024-07-30 11:50 ` Edward Cree [this message]
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=9505522b-de45-cf52-162b-76a3a52a6efe@gmail.com \
--to=ecree.xilinx@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=harishankar.vishwanathan@gmail.com \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=m.shachnai@rutgers.edu \
--cc=martin.lau@linux.dev \
--cc=santosh.nagarakatte@rutgers.edu \
--cc=sdf@fomichev.me \
--cc=shung-hsi.yu@suse.com \
--cc=song@kernel.org \
--cc=srinivas.narayana@rutgers.edu \
--cc=xukuohai@huaweicloud.com \
--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