From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Eduard Zingerman <eddyz87@gmail.com>
Cc: bpf@vger.kernel.org, ast@kernel.org, andrii@kernel.org,
daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com,
yhs@fb.com
Subject: Re: [PATCH bpf-next v4 1/4] bpf: use scalar ids in mark_chain_precision()
Date: Fri, 9 Jun 2023 15:24:43 -0700 [thread overview]
Message-ID: <CAEf4BzY7cfD-hKo7jMpj6O9KhjFKZZ0VxaUKxMFMoLDy2QEogQ@mail.gmail.com> (raw)
In-Reply-To: <20230609210143.2625430-2-eddyz87@gmail.com>
On Fri, Jun 9, 2023 at 2:01 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> Change mark_chain_precision() to track precision in situations
> like below:
>
> r2 = unknown value
> ...
> --- state #0 ---
> ...
> r1 = r2 // r1 and r2 now share the same ID
> ...
> --- state #1 {r1.id = A, r2.id = A} ---
> ...
> if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1
> ...
> --- state #2 {r1.id = A, r2.id = A} ---
> r3 = r10
> r3 += r1 // need to mark both r1 and r2
>
> At the beginning of the processing of each state, ensure that if a
> register with a scalar ID is marked as precise, all registers sharing
> this ID are also marked as precise.
>
> This property would be used by a follow-up change in regsafe().
>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
> include/linux/bpf_verifier.h | 10 +-
> kernel/bpf/verifier.c | 115 ++++++++++++++++++
> .../testing/selftests/bpf/verifier/precise.c | 8 +-
> 3 files changed, 128 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 5fe589e11ac8..73a98f6240fd 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -559,6 +559,11 @@ struct backtrack_state {
> u64 stack_masks[MAX_CALL_FRAMES];
> };
>
> +struct bpf_idset {
> + u32 count;
> + u32 ids[BPF_ID_MAP_SIZE];
> +};
> +
> /* single container for all structs
> * one verifier_env per bpf_check() call
> */
> @@ -590,7 +595,10 @@ struct bpf_verifier_env {
> const struct bpf_line_info *prev_linfo;
> struct bpf_verifier_log log;
> struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
> - struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE];
> + union {
> + struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE];
> + struct bpf_idset idset_scratch;
> + };
> struct {
> int *insn_state;
> int *insn_stack;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index ed79a93398f8..f719de396c61 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -3787,6 +3787,96 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_
> }
> }
>
> +static bool idset_contains(struct bpf_idset *s, u32 id)
> +{
> + u32 i;
> +
> + for (i = 0; i < s->count; ++i)
> + if (s->ids[i] == id)
> + return true;
> +
> + return false;
> +}
> +
> +static int idset_push(struct bpf_idset *s, u32 id)
> +{
> + if (WARN_ON_ONCE(s->count >= ARRAY_SIZE(s->ids)))
> + return -1;
> + s->ids[s->count++] = id;
> + return 0;
> +}
> +
> +static void idset_reset(struct bpf_idset *s)
> +{
> + s->count = 0;
> +}
> +
> +/* Collect a set of IDs for all registers currently marked as precise in env->bt.
> + * Mark all registers with these IDs as precise.
> + */
> +static int mark_precise_scalar_ids(struct bpf_verifier_env *env, struct bpf_verifier_state *st)
> +{
> + struct bpf_idset *precise_ids = &env->idset_scratch;
> + struct backtrack_state *bt = &env->bt;
> + struct bpf_func_state *func;
> + struct bpf_reg_state *reg;
> + DECLARE_BITMAP(mask, 64);
> + int i, fr;
> +
> + idset_reset(precise_ids);
> +
> + for (fr = bt->frame; fr >= 0; fr--) {
> + func = st->frame[fr];
> +
> + bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr));
> + for_each_set_bit(i, mask, 32) {
> + reg = &func->regs[i];
> + if (!reg->id || reg->type != SCALAR_VALUE)
> + continue;
> + if (idset_push(precise_ids, reg->id))
> + return -1;
> + }
> +
> + bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr));
> + for_each_set_bit(i, mask, 64) {
> + if (i >= func->allocated_stack / BPF_REG_SIZE)
> + break;
> + if (!is_spilled_scalar_reg(&func->stack[i]))
> + continue;
> + reg = &func->stack[i].spilled_ptr;
> + if (!reg->id)
> + continue;
> + if (idset_push(precise_ids, reg->id))
> + return -1;
-EFAULT, -1 is -EPERM, super confusing if it ever bubbles up. Same for
idset_push return code, please use more appropriate error code
constants
Other than that, it looks good. Please add my ack once you fix error values:
Acked-by: Andrii Nakryiko <andrii@kernel.org>
> + }
> + }
> +
> + for (fr = 0; fr <= st->curframe; ++fr) {
> + func = st->frame[fr];
> +
> + for (i = BPF_REG_0; i < BPF_REG_10; ++i) {
> + reg = &func->regs[i];
> + if (!reg->id)
> + continue;
> + if (!idset_contains(precise_ids, reg->id))
> + continue;
> + bt_set_frame_reg(bt, fr, i);
> + }
> + for (i = 0; i < func->allocated_stack / BPF_REG_SIZE; ++i) {
> + if (!is_spilled_scalar_reg(&func->stack[i]))
> + continue;
> + reg = &func->stack[i].spilled_ptr;
> + if (!reg->id)
> + continue;
> + if (!idset_contains(precise_ids, reg->id))
> + continue;
> + bt_set_frame_slot(bt, fr, i);
> + }
> + }
> +
> + return 0;
> +}
> +
[...]
next prev parent reply other threads:[~2023-06-09 22:25 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-09 21:01 [PATCH bpf-next v4 0/4] verify scalar ids mapping in regsafe() Eduard Zingerman
2023-06-09 21:01 ` [PATCH bpf-next v4 1/4] bpf: use scalar ids in mark_chain_precision() Eduard Zingerman
2023-06-09 22:24 ` Andrii Nakryiko [this message]
2023-06-09 21:01 ` [PATCH bpf-next v4 2/4] selftests/bpf: check if mark_chain_precision() follows scalar ids Eduard Zingerman
2023-06-09 21:01 ` [PATCH bpf-next v4 3/4] bpf: verify scalar ids mapping in regsafe() using check_ids() Eduard Zingerman
2023-06-09 23:11 ` Andrii Nakryiko
2023-06-09 23:22 ` Eduard Zingerman
2023-06-09 21:01 ` [PATCH bpf-next v4 4/4] selftests/bpf: verify that check_ids() is used for scalars in regsafe() 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=CAEf4BzY7cfD-hKo7jMpj6O9KhjFKZZ0VxaUKxMFMoLDy2QEogQ@mail.gmail.com \
--to=andrii.nakryiko@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=kernel-team@fb.com \
--cc=martin.lau@linux.dev \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).