BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Yonghong Song" <yonghong.song@linux.dev>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v4 08/20] bpf: Walk the exception unwind in the verifier
Date: Mon, 21 Sep 2026 21:40:18 +0000	[thread overview]
Message-ID: <20260921214019.5C01F1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260921210114.1720196-1-yonghong.song@linux.dev>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] bpf: BPF_EXIT in exception cleanup pads bypasses runtime unwinding
- [High] bpf: nested bpf_throw() in landing pads causes kernel NULL pointer dereference
- [Medium] bpf: R0 precision tracking is not cleared across exception edges
--

commit cdb6004b5b8821aea00d57d94b9ac5bcf916b6a4
Author: Yonghong Song <yonghong.song@linux.dev>
Subject: bpf: Walk the exception unwind in the verifier

This commit updates the BPF verifier to walk the exception unwinding path
step for step when bpf_throw() is called. This aligns the verifier with
the runtime unwinder to properly handle landing pads for exception cleanup.

> diff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c
> index 507a366dffa47..bf5e7e6ab78f3 100644
> --- a/kernel/bpf/backtrack.c
> +++ b/kernel/bpf/backtrack.c
[ ... ]
> @@ -909,6 +913,14 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
>  				 */
>  				return 0;
>  			subseq_idx = i;
> +			/* This insn is a landing pad the unwind reached from
> +			 * a throw or a resume hist->unwind_frames frames
> +			 * deeper. No insn stands between the two, so enter
> +			 * those frames here, the way BPF_EXIT enters one.
> +			 */
> +			for (fr = 0; hist && fr < hist->unwind_frames; fr++)
> +				if (bt_subprog_enter(bt))
> +					return -EFAULT;
>  			i = get_prev_insn_idx(st, i, &history);
>  			if (i == -ENOENT)
>  				break;

[Severity: Medium]
When traversing the exception edge here, does the backtrack correctly clear
the precision tracking for R0 in the pad's frame?

When returning from a throw to a landing pad, R0 is initialized to
BPF_PAD_ENTRY_R0 by the kernel unwinder. Since its precision might be
tracked if used in a conditional jump in the pad, this backtrack loop uses
bt_subprog_enter(bt) but does not appear to clear R0's precision mask in
the pad's frame.

This could leave R0 erroneously tracked in the pad's frame as the backtrack
proceeds, eventually reaching the program entry and triggering a
verifier_bug() that rejects valid BPF programs with -EFAULT.

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 680ae191aa3f5..2bc08c18ebc89 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> @@ -14585,7 +14588,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
>  		env->prog->call_session_cookie = true;
>  
>  	if (bpf_is_throw_kfunc(insn))
> -		return process_bpf_exit_full(env, NULL, true);
> +		return unwind_step(env, insn_idx, &env->insn_idx);
>  
>  	return 0;
>  }

[Severity: High]
Is there anything preventing a nested exception from being thrown here?

There doesn't seem to be a check for env->cur_state->unwinding before
processing bpf_throw(), which allows a program to throw an exception from
within a landing pad.

At runtime, the landing pad is executed via arch_bpf_run_cleanup_pad(),
placing kernel frames on the call stack above the BPF frames. A nested call
to bpf_throw() would invoke arch_bpf_stack_walk().

Since it would encounter the non-BPF frame for arch_bpf_run_cleanup_pad(),
bpf_prog_ksym_find() returns NULL. With ctx->cnt being non-zero, the walk
halts prematurely, causing a blind dereference of ctx.aux->bpf_exception_cb
and leading to a kernel NULL pointer dereference.

[ ... ]
> @@ -18522,25 +18624,11 @@ static int process_bpf_exit_full(struct bpf_verifier_env *env,
>  	 * for which reference_state must match caller reference
>  	 * state when it exits.
>  	 */
> -	int err = check_resource_leak(env, exception_exit,
> -				      exception_exit || !env->cur_state->curframe,
> -				      exception_exit ? "bpf_throw" :
> +	int err = check_resource_leak(env, false, !env->cur_state->curframe,
>  				      "BPF_EXIT instruction in main prog");
>  	if (err)
>  		return err;
>  
> -	/* The side effect of the prepare_func_exit which is
> -	 * being skipped is that it frees bpf_func_state.
> -	 * Typically, process_bpf_exit will only be hit with
> -	 * outermost exit. copy_verifier_state in pop_stack will
> -	 * handle freeing of any extra bpf_func_state left over
> -	 * from not processing all nested function exits. We
> -	 * also skip return code checks as they are not needed
> -	 * for exceptional exits.
> -	 */
> -	if (exception_exit)
> -		return PROCESS_BPF_EXIT;
> -
>  	if (env->cur_state->curframe) {
>  		/* exit from nested function */
>  		err = prepare_func_exit(env, &env->insn_idx);
[ ... ]
> @@ -18747,7 +18837,7 @@ static int do_check_insn(struct bpf_verifier_env *env, bool *do_print_state)
>  				env->insn_idx += insn->imm + 1;
>  			return INSN_IDX_UPDATED;
>  		} else if (opcode == BPF_EXIT) {
> -			return process_bpf_exit_full(env, do_print_state, false);
> +			return process_bpf_exit_full(env, do_print_state);
>  		}
>  		return check_cond_jmp_op(env, insn, &env->insn_idx);
>  	}

[Severity: High]
Are we correctly handling BPF_EXIT when an exception is in flight?

Because process_bpf_exit_full() is called unconditionally without checking
if env->cur_state->unwinding is true, the verifier treats BPF_EXIT from a
landing pad as a normal subprogram return (when curframe > 0).

It pops the frame and continues verifying the caller's instructions, where
an attacker might place lock releases to satisfy check_resource_leak().

At runtime, BPF_EXIT emits a bare 'ret' instruction. When executed from
arch_bpf_run_cleanup_pad(), it behaves like bpf_unwind_resume() by
returning control to the kernel unwinder, which silently discards the
caller frame without executing it.

This discrepancy could allow BPF programs to bypass verifier resource
checks and leak locks or references at runtime.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260921210033.1715000-1-yonghong.song@linux.dev?part=8

  reply	other threads:[~2026-09-21 21:40 UTC|newest]

Thread overview: 80+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21 21:00 [PATCH bpf-next v4 00/20] bpf: Run exception cleanup landing pads when bpf_throw() unwinds Yonghong Song
2026-09-21 21:00 ` [PATCH bpf-next v4 01/20] bpf: Accept the compiler's exception cleanup table at program load Yonghong Song
2026-09-21 21:56   ` bot+bpf-ci
2026-09-22  3:27     ` Yonghong Song
2026-09-21 21:00 ` [PATCH bpf-next v4 02/20] bpf: Add the bpf_unwind_resume() kfunc Yonghong Song
2026-09-21 21:56   ` bot+bpf-ci
2026-09-22  3:31     ` Yonghong Song
2026-09-21 21:00 ` [PATCH bpf-next v4 03/20] bpf: Add lookups for exception cleanup resumes and landing pads Yonghong Song
2026-09-22  4:04   ` Alexei Starovoitov
2026-09-22  5:28     ` Yonghong Song
2026-09-21 21:00 ` [PATCH bpf-next v4 04/20] bpf: Prepare for an exception cleanup table before the CFG walk Yonghong Song
2026-09-22 18:27   ` Eduard Zingerman
2026-09-23  3:07     ` Yonghong Song
2026-09-23  3:54       ` Eduard Zingerman
2026-09-23  4:05         ` Yonghong Song
2026-09-21 21:00 ` [PATCH bpf-next v4 05/20] bpf: Make exception landing pads reachable in the CFG Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 06/20] bpf: Explore the landing pads no call site reaches Yonghong Song
2026-09-21 23:58   ` Eduard Zingerman
2026-09-22  3:32     ` Yonghong Song
2026-09-22  4:10       ` Eduard Zingerman
2026-09-21 21:01 ` [PATCH bpf-next v4 07/20] bpf: Refuse exception cleanup shapes bpf_throw() cannot dispatch Yonghong Song
2026-09-21 21:20   ` sashiko-bot
2026-09-22  3:39     ` Yonghong Song
2026-09-21 21:56   ` bot+bpf-ci
2026-09-22  3:44     ` Yonghong Song
2026-09-22  0:30   ` Eduard Zingerman
2026-09-22  3:45     ` Yonghong Song
2026-09-22 21:43       ` Eduard Zingerman
2026-09-23  3:11         ` Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 08/20] bpf: Walk the exception unwind in the verifier Yonghong Song
2026-09-21 21:40   ` sashiko-bot [this message]
2026-09-22  4:17     ` Yonghong Song
2026-09-21 21:56   ` bot+bpf-ci
2026-09-22  5:21     ` Yonghong Song
2026-09-22  4:08   ` Alexei Starovoitov
2026-09-22  5:25     ` Yonghong Song
2026-09-22 21:53       ` Eduard Zingerman
2026-09-23  3:18         ` Yonghong Song
2026-09-22 23:43   ` Eduard Zingerman
2026-09-23  3:21     ` Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 09/20] bpf: Refuse a private stack for a program with an exception cleanup table Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 10/20] bpf: Dispatch exception cleanup pads from bpf_throw() Yonghong Song
2026-09-22 21:38   ` Eduard Zingerman
2026-09-23  3:22     ` Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 11/20] bpf, x86: Dispatch exception cleanup pads at run time Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 12/20] bpf, arm64: " Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 13/20] libbpf: Resolve the compiler's _Unwind_Resume to the kernel's kfunc Yonghong Song
2026-09-21 21:13   ` sashiko-bot
2026-09-21 21:01 ` [PATCH bpf-next v4 14/20] libbpf: Add cleanup_info to bpf_prog_load_opts Yonghong Song
2026-09-21 21:01 ` [PATCH bpf-next v4 15/20] libbpf: Collect .bpf_cleanup records and pass them to the kernel Yonghong Song
2026-09-21 21:20   ` sashiko-bot
2026-09-21 21:01 ` [PATCH bpf-next v4 16/20] libbpf: Carry the exception cleanup table through the light skeleton Yonghong Song
2026-09-21 21:02 ` [PATCH bpf-next v4 17/20] libbpf: Let the static linker carry .bpf_cleanup relocations Yonghong Song
2026-09-21 21:02 ` [PATCH bpf-next v4 18/20] selftests/bpf: Add an end-to-end .bpf_cleanup exception test Yonghong Song
2026-09-21 21:22   ` sashiko-bot
2026-09-22  5:26     ` Yonghong Song
2026-09-21 21:56   ` bot+bpf-ci
2026-09-21 21:02 ` [PATCH bpf-next v4 19/20] selftests/bpf: Cover the exception cleanup shapes the chain does not reach Yonghong Song
2026-09-21 21:19   ` sashiko-bot
2026-09-21 21:02 ` [PATCH bpf-next v4 20/20] selftests/bpf: Load an exception cleanup program from a light skeleton Yonghong Song
2026-09-22  1:08 ` [PATCH bpf-next v4 00/20] bpf: Run exception cleanup landing pads when bpf_throw() unwinds Eduard Zingerman
2026-09-22  2:16   ` Alexei Starovoitov
2026-09-22  2:31     ` Kumar Kartikeya Dwivedi
2026-09-22 21:44       ` Alexei Starovoitov
2026-09-23  4:36         ` Kumar Kartikeya Dwivedi
2026-09-23  4:54           ` Alexei Starovoitov
2026-09-23  5:20             ` Kumar Kartikeya Dwivedi
2026-09-23  6:16             ` Eduard Zingerman
2026-09-23  6:44               ` Kumar Kartikeya Dwivedi
2026-09-22  4:27     ` Eduard Zingerman
2026-09-22 21:47       ` Alexei Starovoitov
2026-09-22 23:08         ` Eduard Zingerman
2026-09-22 23:37           ` Alexei Starovoitov
2026-09-23  0:04             ` Eduard Zingerman
2026-09-23 19:04               ` Eduard Zingerman
2026-09-23 19:24                 ` Andrii Nakryiko
2026-09-23 19:34                   ` Kumar Kartikeya Dwivedi
2026-09-23 21:34                     ` Alexei Starovoitov
2026-09-23 22:00                       ` Eduard Zingerman
2026-09-23 23:22                         ` 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=20260921214019.5C01F1F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --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