From: sashiko-bot@kernel.org
To: "Kumar Kartikeya Dwivedi" <memxor@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v1 21/29] bpf: Support callx when a callee releases resources
Date: Wed, 11 Nov 2026 17:13:24 +0000 [thread overview]
Message-ID: <sashiko-outbox-209387@kernel.org> (raw)
In-Reply-To: <0847523e18df54ccf22c46885001d309841a60c2.1794399387.git.memxor@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] bpf: resource leak via bypassed lent check in
bpf_frame_desc_record_callx()
- [Medium] bpf: hidden slot cleared without release in
bpf_frame_desc_record_callx()
--
commit 10ca45cf5c85b803527fe102c801dcc6b5d2cc99
Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Support callx when a callee releases resources
This commit extends frame descriptor tracking to support callx instructions
whose target subprogs transfer or release caller-held resources, rejecting
programs when targets disagree on whether an argument reference is consumed.
> diff --git a/kernel/bpf/frame_desc.c b/kernel/bpf/frame_desc.c
> index 6679f134b14ee..11b2546bc179f 100644
> --- a/kernel/bpf/frame_desc.c
> +++ b/kernel/bpf/frame_desc.c
[ ... ]
> @@ -981,6 +983,56 @@ int bpf_frame_desc_record_call(struct bpf_verifier_env *env, struct bpf_verifier
> return 0;
> }
>
> +/*
> + * The callx at insn @callsite of the current frame calls @subprog, one of the
> + * subprogs it may call. What the frame puts in front of the callx runs
> + * whichever it calls: the insns that take what it hands over out of its slot,
> + * and the one that empties the slot of what a callee releases without being
> + * handed it, see foreign_cleared(). So note what this subprog leaves with the
> + * frame:
> + *
> + * - What the frame holds and passes it in an argument that it does not
> + * release through. Another subprog may be handed it in that argument, and
> + * the slot would be emptied for this one as well, see slot_can_be_kept().
> + * - All that the frame holds, when the subprog releases nothing of its
> + * callers'. It is not verified in their context then, so its return has
> + * no frame to say so, see bpf_frame_desc_record_exit().
> + */
> +int bpf_frame_desc_record_callx(struct bpf_verifier_env *env, int subprog, int callsite)
> +{
> + const struct bpf_subprog_info *sub = &env->subprog_info[subprog];
> + struct bpf_verifier_state *st = env->cur_state;
> + const struct bpf_func_state *frame = st->frame[st->curframe];
> + const struct bpf_reference_state *ref;
> + struct bpf_res_call *c;
> + int i, k;
> + u8 lent;
> + s16 adj;
> +
> + if (!env->describe_frames || st->speculative)
> + return 0;
> + for (i = 0; i < st->acquired_refs; i++) {
> + ref = &st->refs[i];
> + if (ref->frameno != st->curframe || !ref->acq)
> + continue;
> + lent = 0;
> + for (k = BPF_REG_1; k <= BPF_REG_5; k++)
> + if (!(sub->consumes & BIT(k)) && ref->type == REF_TYPE_PTR &&
> + !(env->res_acqs[ref->acq - 1].flags & BPF_RES_F_ARG) &&
> + reg_ref_off(&frame->regs[k], ref->id, &adj))
> + lent |= BIT(k);
[Severity: High]
Can a caller's hidden slot still be cleared before a callx to a subprog that
does not consume Rk, leaking the reference on a later bpf_throw()?
When one target of a callx consumes Rk, emit_release() emits instructions
before the callx that compare the 64-bit runtime value of Rk with the caller's
hidden slot and zero the slot if they match. However,
bpf_frame_desc_record_callx() only sets BIT(k) in lent when reg_ref_off()
succeeds in the verifier state at the callx.
If another path reaches the same callx to invoke a non-consuming subprog while
Rk still holds the handle address at runtime, but its verifier state fails
reg_ref_off() (for instance, Rk is NOT_INIT after merging with a path that did
not set Rk, or after an earlier call to a no-op subprog cleared caller-saved
registers in the verifier while leaving Rk intact in hardware), BIT(k) is not
set in c->lent. slot_can_be_kept() then accepts the program, the pre-callx
sequence zeroes the caller's hidden slot at runtime before the non-consuming
subprog runs, and a subsequent bpf_throw() fails to release the resource.
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 1f41095f4f1fa..51896b2001614 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11451,9 +11451,10 @@ static int setup_func_entry(struct bpf_verifier_env *env, int subprog, int calls
> err = set_callee_state_cb(env, caller, callee, callsite);
> if (err)
> goto err_out;
> - /* a plain call hands the callee what it releases of the caller's, see frame_desc.c */
> + /* the call of a subprog hands it what it releases of the caller's, see frame_desc.c */
> err = bpf_frame_desc_record_call(env, set_callee_state_cb == set_callee_state &&
> - bpf_pseudo_call(&env->prog->insnsi[callsite]) ? state : NULL,
> + (bpf_pseudo_call(&env->prog->insnsi[callsite]) ||
> + bpf_is_callx(&env->prog->insnsi[callsite])) ? state : NULL,
> callee, callsite);
[Severity: Medium]
What happens if a callx invokes a subprog with sub->consumes & BIT(k) set on a
path where Rk holds the runtime address of a caller-held reference without
satisfying reg_ref_off()?
Because sub->consumes & BIT(k) is set, bpf_frame_desc_record_callx() skips Rk.
In bpf_frame_desc_record_call(), if one callx path passes the caller's
reference in Rk (recording rel_add() at callsite, with the callee releasing it
without needing its own hidden slot) and a second path passes the same runtime
pointer in Rk in a form that fails reg_ref_off() (such as a pointer with a
variable offset in [0, 1] that is 0 at runtime, or an untrusted pointer from
bpf_rdonly_cast()) on a branch where the callee does not release it,
bpf_frame_desc_record_call() only sets sub->entry_none |= BIT(k) and leaves
the reference with the caller.
Because the callee's BPF_RES_F_ENTRY acquisition does not need a hidden slot
of its own, bpf_frame_desc_resolve() never checks sub->entry_none, and
handed_back is not set on exit. The emit_release() instructions placed before
the callx still zero the caller's hidden slot at runtime on the second path,
leaking the reference if the caller later throws.
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1794399387.git.memxor@gmail.com?part=21
next prev parent reply other threads:[~2026-11-11 17:13 UTC|newest]
Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 12:56 [PATCH bpf-next v1 00/29] Exceptions - Resource Cleanup - Redux Kumar Kartikeya Dwivedi
2026-11-11 12:56 ` [PATCH bpf-next v1 01/29] bpf: Record where JITs save callee-saved registers Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 02/29] bpf: Add bpf_throw_unwind() and an arch entry hook Kumar Kartikeya Dwivedi
2026-11-11 14:45 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 03/29] bpf, x86: Capture registers in a native bpf_throw() entry Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 04/29] bpf, arm64: " Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 05/29] bpf: Restore callee-saved registers from unwound frames Kumar Kartikeya Dwivedi
2026-11-11 14:41 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 06/29] bpf: Keep last insn's aux data in add_hidden_subprog() Kumar Kartikeya Dwivedi
2026-11-11 14:38 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 07/29] bpf: Add one allocator for hidden stack slots Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 15:15 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 08/29] bpf: Add flags and release kfuncs to the dtor registry Kumar Kartikeya Dwivedi
2026-11-11 13:33 ` bot+bpf-ci
2026-11-11 15:36 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 09/29] bpf: Register cleanup destructors for more types Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 15:00 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 10/29] bpf: Record where JITed frames keep the BPF stack Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 11/29] bpf: Give every reference an owner frame Kumar Kartikeya Dwivedi
2026-11-11 13:33 ` bot+bpf-ci
2026-11-11 12:57 ` [PATCH bpf-next v1 12/29] bpf: Release resources in hidden slots on bpf_throw() Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 15:30 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 13/29] bpf: Track held resources in hidden stack slots Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 16:12 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 14/29] bpf: Describe held resources at throw sites Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 12:57 ` [PATCH bpf-next v1 15/29] bpf: Describe handles in registers " Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 16:11 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 16/29] bpf: Describe locks " Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 16:04 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 17/29] bpf: Apply hidden slot limits only when a slot is needed Kumar Kartikeya Dwivedi
2026-11-11 16:31 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 18/29] bpf: Allow a callee to leave resources with its caller Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 16:41 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 19/29] bpf: Allow a callee to release its caller's resources Kumar Kartikeya Dwivedi
2026-11-11 17:02 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 20/29] bpf: Transfer a reference to the callee that releases it Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 16:57 ` sashiko-bot
2026-11-11 12:57 ` [PATCH bpf-next v1 21/29] bpf: Support callx when a callee releases resources Kumar Kartikeya Dwivedi
2026-11-11 14:04 ` bot+bpf-ci
2026-11-11 17:13 ` sashiko-bot [this message]
2026-11-11 12:57 ` [PATCH bpf-next v1 22/29] selftests/bpf: Test rejected throws that hold resources Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 23/29] selftests/bpf: Test resource cleanup on bpf_throw() Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 24/29] selftests/bpf: Test cleanup of handles on the stack Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 25/29] selftests/bpf: Test cleanup of handles in registers Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 26/29] selftests/bpf: Test callees releasing caller resources Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 27/29] selftests/bpf: Test resources a callee leaves with its caller Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 28/29] selftests/bpf: Test cleanup of locks described at sites Kumar Kartikeya Dwivedi
2026-11-11 12:57 ` [PATCH bpf-next v1 29/29] selftests/bpf: Test callee releases through callx Kumar Kartikeya Dwivedi
2026-11-11 20:33 ` [PATCH bpf-next v1 00/29] Exceptions - Resource Cleanup - Redux Alexei Starovoitov
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=sashiko-outbox-209387@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=memxor@gmail.com \
--cc=sashiko-reviews@lists.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 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.