BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Kumar Kartikeya Dwivedi" <memxor@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v1 03/20] bpf: Refuse bpf_task_park() in callbacks
Date: Tue, 10 Nov 2026 00:40:06 +0000	[thread overview]
Message-ID: <sashiko-outbox-205882@kernel.org> (raw)
In-Reply-To: <d7e8470a75a3ff4b2e65066f6ba6edb4e5bc14ef.1794269506.git.memxor@gmail.com>

Thank you for your contribution! Sashiko AI review found no new issues
in this patch, but noticed 2 related pre-existing issues it does not
introduce:
- [Critical] bpf: missing in_rbtree_lock_required_cb() check in
  check_func_arg() [1]
- [Critical] bpf: missing parent_id propagation in check_kfunc_call()
  [2]
--

commit 73a7888b7c16b7854db73a1efaa1ffed4dc01be8
Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>

bpf: Refuse bpf_task_park() in callbacks

This commit rejects calls to bpf_task_park() inside synchronous,
asynchronous, and exception callback frames by walking the active frames in
the verifier state.

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index e90cc127aedb8..b42782c7f209d 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11222,6 +11222,31 @@ static void invalidate_non_owning_refs(struct bpf_verifier_env *env)
>  	}));
>  }
>  
> +/*
> + * bpf_task_park() is confined to the main body of the program and the
> + * functions it calls directly. A callback runs from kernel code that holds
> + * state of its own around the call, an iteration position, a work item or
> + * timer that owns the program only through Tasks Trace RCU, an exiting task,
> + * none of it audited against a sleep that drops the program's protection.
> + * Refuse the park in any callback frame, synchronous, asynchronous or
> + * exception. Asynchronous callbacks are verified as a state of their own
> + * with the callback as frame 0, so the walk over the frames sees them too.
> + */
> +static bool in_callback_frames(struct bpf_verifier_env *env)
> +{
> +	struct bpf_verifier_state *vstate = env->cur_state;
> +	int i;
> +
> +	for (i = 0; i <= vstate->curframe; i++) {
> +		struct bpf_func_state *frame = vstate->frame[i];
> +
> +		if (frame->in_callback_fn || frame->in_async_callback_fn ||
> +		    frame->in_exception_callback_fn)
> +			return true;
> +	}
> +	return false;
> +}

[Severity: Critical]
This problem wasn't introduced by this patch, but can an rbtree comparator
callback corrupt the tree via [1] because check_func_arg() skips
in_rbtree_lock_required_cb() for bpf_rbtree_add_impl()?

kernel/bpf/verifier.c:check_func_arg() {
	...
	case ARG_PTR_TO_RB_NODE:
		if (is_bpf_rbtree_add_kfunc(meta->func_id)) {
			if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
				verbose(env, "%s expected pointer to allocated object\n",
					reg_arg_name(env, argno));
				return -EINVAL;
			}
			if (!reg_is_referenced(env, reg)) {
				verbose(env, "allocated object must be referenced\n");
				return -EINVAL;
			}
		} else {
			...
			if (in_rbtree_lock_required_cb(env)) {
				verbose(env, "%s not allowed in rbtree cb\n", meta->func_name);
				return -EINVAL;
			}
		}
}

While the outer __bpf_rbtree_add() is mid-traversal inside bpf_call_cb(),
the comparator callback can acquire an owning node reference (for example,
via bpf_list_pop_front()) and invoke bpf_rbtree_add_impl() with a second
comparator subprogram. The nested insertion links the node and rebalances
the tree under the already-held lock, leaving the outer __bpf_rbtree_add()
to finish linking with stale parent, link, and leftmost state when the
callback returns.

> @@ -16366,6 +16391,12 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
>  	}
>  
>  	if (is_bpf_task_park_kfunc(meta.func_id)) {
> +		if (in_callback_frames(env)) {
> +			verbose(env, "bpf_task_park() is not allowed in a callback\n");
> +			bpf_diag_policy(env, insn_idx, "kfunc bpf_task_park", "the call is in a callback",
> +					"Call bpf_task_park() from the main program or from a function it calls directly, not from a callback.");
> +			return -EINVAL;
> +		}
>  		err = check_park_stack_objects(env, insn_idx);
>  		if (err)
>  			return err;

[Severity: Critical]
This problem wasn't introduced by this patch, but does check_kfunc_call()
fail to track the lifetime of a returned PTR_TO_MEM register [2] when
the kfunc argument is a borrowed pointer?

kernel/bpf/verifier.c:check_kfunc_call() {
			...
			mark_reg_known_zero(env, regs, BPF_REG_0);
			regs[BPF_REG_0].type = PTR_TO_MEM;
			regs[BPF_REG_0].mem_size = meta.ret_mem.size;
			...
			if (meta.ref_obj.id) {
				err = validate_ref_obj(env, &meta.ref_obj);
				if (err)
					return err;
				regs[BPF_REG_0].parent_id = meta.ref_obj.id;
			}
}

For a borrowed pointer argument, meta.ref_obj.id is 0 and the parent
object's lifetime is recorded in meta.ref_obj.parent_id instead. Ignoring
meta.ref_obj.parent_id leaves regs[BPF_REG_0].parent_id unset, so releasing
or invalidating the underlying parent object does not invalidate R0,
allowing a use-after-free through the returned PTR_TO_MEM pointer.

[1] https://sashiko.dev/#/bug/linux-eb46b3eb-92d0-4fac-b401-30327c613b94
[2] https://sashiko.dev/#/bug/linux-3da483d6-33c8-4529-a20e-81cdfb7a8ed3

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1794269506.git.memxor@gmail.com?part=3

  reply	other threads:[~2026-11-10  0:40 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10  0:27 [PATCH bpf-next v1 00/20] BPF kthreads and waitqueues Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 01/20] bpf: Add bpf_task_park() and bpf_task_wake() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 02/20] bpf: Invalidate what a bpf_task_park() sleep may free Kumar Kartikeya Dwivedi
2026-11-10  0:49   ` sashiko-bot
2026-11-10  0:27 ` [PATCH bpf-next v1 03/20] bpf: Refuse bpf_task_park() in callbacks Kumar Kartikeya Dwivedi
2026-11-10  0:40   ` sashiko-bot [this message]
2026-11-10  0:27 ` [PATCH bpf-next v1 04/20] bpf: Propagate bpf_task_park() through global functions Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 05/20] bpf: Verify a function that parks in the context of its caller Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 06/20] bpf: Defer bpf_task_wake() to irq_work when IRQs are disabled Kumar Kartikeya Dwivedi
2026-11-10  1:16   ` sashiko-bot
2026-11-10  0:27 ` [PATCH bpf-next v1 07/20] bpf: Keep programs that park away from per-CPU state and tail calls Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 08/20] bpf: Register bpf_task_park() for syscall programs Kumar Kartikeya Dwivedi
2026-11-10  1:21   ` sashiko-bot
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 09/20] bpf: Register bpf_task_wake() for all program types Kumar Kartikeya Dwivedi
2026-11-10  1:39   ` sashiko-bot
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 10/20] bpf: Add BPF kthreads for syscall programs Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 11/20] bpf: Let a BPF kthread sleep in bpf_task_park() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 12/20] bpf: Add bpf_kthread_bind() to pin a BPF kthread to a CPU Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 13/20] bpf: Add bpf_kthread_attach_cgroup() to place a BPF kthread in a cgroup Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 14/20] selftests/bpf: Test bpf_task_park() and bpf_task_wake() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 15/20] selftests/bpf: Test what survives bpf_task_park() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 16/20] selftests/bpf: Test bpf_task_park() across functions and callbacks Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 17/20] selftests/bpf: Test bpf_task_wake() from tracing programs Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 18/20] selftests/bpf: Test BPF kthreads Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 19/20] selftests/bpf: Test bpf_kthread_bind() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 20/20] selftests/bpf: Test bpf_kthread_attach_cgroup() Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci

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-205882@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox