public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Eduard Zingerman <eddyz87@gmail.com>
To: Amery Hung <ameryhung@gmail.com>
Cc: bpf@vger.kernel.org, netdev@vger.kernel.org,
	alexei.starovoitov@gmail.com, 	andrii@kernel.org,
	daniel@iogearbox.net, memxor@gmail.com, martin.lau@kernel.org,
		mykyta.yatsenko5@gmail.com, kernel-team@meta.com
Subject: Re: [PATCH bpf-next v3 4/9] bpf: Refactor object relationship tracking and fix dynptr UAF bug
Date: Tue, 28 Apr 2026 00:05:55 -0700	[thread overview]
Message-ID: <4386cf7de9b7fa5a03191bf97d7f5fda1f39de34.camel@gmail.com> (raw)
In-Reply-To: <CAMB2axPaDEG_oKLxhcRmivv+YK_ExxNVY_KpSf1vvgLiPq1tvg@mail.gmail.com>

On Mon, 2026-04-27 at 13:21 -0700, Amery Hung wrote:
> On Fri, Apr 24, 2026 at 3:48 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
> > 
> > On Tue, 2026-04-21 at 15:10 -0700, Amery Hung wrote:
> > 
> > Tbh, I find current state of affairs with id/ref_obj_id/parent_id hard
> > to follow. The release_reference() is an improvement, but the means by
> > which the fields are propagated to bpf_reg_state objects are convoluted.
> > I wonder if having a separate "object table" in bpf_verifier_state and
> > having bpf_reg_state->id refer to objects within this table would make
> > things more straight forward.
> 
> I think this is a good idea in the long term. First, we need to make
> id a stable and unique object identifier (i.e., always assign id to
> objects; different objects have different ids). Then, we can create
> the object table indexed by id and each entry contains the ref_obj_id
> and parent_id moved from bpf_reg_state. Then, there will be helpers
> managing the lifetime, relationship (e.g., bpf_obj_create,
> bpf_obj_release, bpf_obj_clone) with clear semantics to centralize how
> id,parent_id,ref_obj_id are manipulated.
> 
> If this makes sense, I can send this as a follow up patchset.

I'd play with it a bit, might make sense if we move a lot of objects
into this table. E.g. forgo find_good_pkt_pointers() and keep packet
info as one of the objects, etc.  On the other hand, dynptr and iters
are inherently stack allocated objects, so it might be the case that
the final implementation would be an over-complication.

[...]

> > >  static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > -                                enum bpf_arg_type arg_type, int insn_idx, int clone_ref_obj_id)
> > > +                                enum bpf_arg_type arg_type, int insn_idx, int parent_id,
> > > +                                struct bpf_dynptr_desc *dynptr)
> > 
> > Having both parent_id and dynptr->parent_id as parameters of this
> > function is very confusing, but I don't have a suggestion on how to
> > better deal with it.
> 
> Does tweaking the argument name and reorder the if-else block make it
> more obvious how these two arguments are used?

Idk, let's go with your original code, maybe?  The eventual goal is to
have a unified handling for both helpers and kfuncs, right?
Meaning that these would be packed into some common arg_info_meta,
with some comments on the structure fields should look ok.

[...]

> > > +/* Release id and objects referencing the id iteratively in a DFS manner */
> > > +static int release_reference(struct bpf_verifier_env *env, int id)
> > > +{
> > > +     u32 mask = (1 << STACK_SPILL) | (1 << STACK_DYNPTR);
> > >       struct bpf_verifier_state *vstate = env->cur_state;
> > > +     struct bpf_idmap *idstack = &env->idmap_scratch;
> > > +     struct bpf_stack_state *stack;
> > >       struct bpf_func_state *state;
> > >       struct bpf_reg_state *reg;
> > > -     int err;
> > > +     int root_id = id, err;
> > > 
> > > -     err = release_reference_nomark(vstate, ref_obj_id);
> > > -     if (err)
> > > -             return err;
> > > +     idstack->cnt = 0;
> > > +     idstack_push(idstack, id);
> > > 
> > > -     bpf_for_each_reg_in_vstate(vstate, state, reg, ({
> > > -             if (reg->ref_obj_id == ref_obj_id)
> > > -                     mark_reg_invalid(env, reg);
> > > -     }));
> > > +     if (find_reference_state(vstate, id))
> > > +             WARN_ON_ONCE(release_reference_nomark(vstate, id));
> > > +
> > > +     while ((id = idstack_pop(idstack))) {
> > > +             bpf_for_each_reg_in_vstate_mask(vstate, state, reg, stack, mask, ({
> > > +                     if (reg->id != id && reg->parent_id != id && reg->ref_obj_id != id)
> > > +                             continue;
> > > +
> > > +                     if (reg->ref_obj_id && id != root_id) {
> > > +                             struct bpf_reference_state *ref_state;
> > > +
> > > +                             ref_state = find_reference_state(env->cur_state, reg->ref_obj_id);
> > > +                             verbose(env, "Unreleased reference id=%d alloc_insn=%d when releasing id=%d\n",
> > > +                                     ref_state->id, ref_state->insn_idx, root_id);
> > > +                             return -EINVAL;
> > > +                     }
> > > +
> > > +                     if (reg->id != id) {
> > > +                             err = idstack_push(idstack, reg->id);
> > > +                             if (err)
> > > +                                     return err;
> > > +                     }
> > > +
> > > +                     if (!stack || stack->slot_type[BPF_REG_SIZE - 1] == STACK_SPILL)
> > > +                             mark_reg_invalid(env, reg);
> > > +                     else if (stack->slot_type[BPF_REG_SIZE - 1] == STACK_DYNPTR)
> > > +                             invalidate_dynptr(env, state, stack);
> > 
> > invalidate_dynptr() rewrites to stack slots, can it be the case that
> > this body of bpf_for_each_reg_in_vstate_mask() is computed for first
> > and second dynptr stack slots, hence triggering invalidate_dynptr() to
> > rewrite three slots instead of two?
> 
> invalidate_dynptr() will mark the two stack slots as STACK_INVALID so
> I didn't bother to check whether it is the first slot or not. Am I
> missing anything?

Oh, right, the == STACK_DYNPTR won't fire for the second slot.
Sorry for the noise.

[...]

  reply	other threads:[~2026-04-28  7:05 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-21 22:10 [PATCH bpf-next v3 0/9] Refactor verifier object relationship tracking Amery Hung
2026-04-21 22:10 ` [PATCH bpf-next v3 1/9] bpf: Unify dynptr handling in the verifier Amery Hung
2026-04-21 22:52   ` bot+bpf-ci
2026-04-23 14:56   ` Mykyta Yatsenko
2026-04-24  0:04   ` Andrii Nakryiko
2026-04-24  5:34     ` Amery Hung
2026-04-24 16:22       ` Andrii Nakryiko
2026-04-21 22:10 ` [PATCH bpf-next v3 2/9] bpf: Assign reg->id when getting referenced kptr from ctx Amery Hung
2026-04-22 21:46   ` Eduard Zingerman
2026-04-22 22:45     ` Amery Hung
2026-04-22 22:50       ` Eduard Zingerman
2026-04-23 22:46         ` Amery Hung
2026-04-24  0:04   ` Andrii Nakryiko
2026-04-21 22:10 ` [PATCH bpf-next v3 3/9] bpf: Preserve reg->id of pointer objects after null-check Amery Hung
2026-04-21 22:52   ` bot+bpf-ci
2026-04-22 22:46     ` Eduard Zingerman
2026-04-24  0:04   ` Andrii Nakryiko
2026-04-21 22:10 ` [PATCH bpf-next v3 4/9] bpf: Refactor object relationship tracking and fix dynptr UAF bug Amery Hung
2026-04-23 18:19   ` Mykyta Yatsenko
2026-04-23 18:44     ` Amery Hung
2026-04-24  0:04       ` Andrii Nakryiko
2026-04-24  6:46         ` Amery Hung
2026-04-27 20:23         ` Amery Hung
2026-04-24 22:48   ` Eduard Zingerman
2026-04-27 20:21     ` Amery Hung
2026-04-28  7:05       ` Eduard Zingerman [this message]
2026-04-21 22:10 ` [PATCH bpf-next v3 5/9] bpf: Remove redundant dynptr arg check for helper Amery Hung
2026-04-21 22:10 ` [PATCH bpf-next v3 6/9] selftests/bpf: Test creating dynptr from dynptr data and slice Amery Hung
2026-04-21 22:10 ` [PATCH bpf-next v3 7/9] selftests/bpf: Test using dynptr after freeing the underlying object Amery Hung
2026-04-21 22:10 ` [PATCH bpf-next v3 8/9] selftests/bpf: Test using slice after invalidating dynptr clone Amery Hung
2026-04-21 22:10 ` [PATCH bpf-next v3 9/9] selftests/bpf: Test using file dynptr after the reference on file is dropped Amery Hung
2026-04-24  0:04 ` [PATCH bpf-next v3 0/9] Refactor verifier object relationship tracking Andrii Nakryiko
2026-04-24  0:55 ` Alexei Starovoitov
2026-04-24  5:44   ` Amery Hung
2026-04-24 13:55     ` Alexei Starovoitov
2026-04-24 16:19       ` Amery Hung

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=4386cf7de9b7fa5a03191bf97d7f5fda1f39de34.camel@gmail.com \
    --to=eddyz87@gmail.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=ameryhung@gmail.com \
    --cc=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@meta.com \
    --cc=martin.lau@kernel.org \
    --cc=memxor@gmail.com \
    --cc=mykyta.yatsenko5@gmail.com \
    --cc=netdev@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox