BPF List
 help / color / mirror / Atom feed
From: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>
To: "Kumar Kartikeya Dwivedi" <memxor@gmail.com>, <bpf@vger.kernel.org>
Cc: "Alexei Starovoitov" <ast@kernel.org>,
	"Andrii Nakryiko" <andrii@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Eduard Zingerman" <eddyz87@gmail.com>,
	"Emil Tsalapatis" <emil@etsalapatis.com>, <kkd@meta.com>,
	<kernel-team@meta.com>
Subject: Re: [PATCH bpf-next v2 10/17] bpf: Report Resource Lifetime reference leaks
Date: Fri, 19 Jun 2026 16:42:33 -0700	[thread overview]
Message-ID: <DJDFA66W97OU.2VSS5QIMHBXCJ@gmail.com> (raw)
In-Reply-To: <20260619205934.1312876-11-memxor@gmail.com>

On Fri Jun 19, 2026 at 1:59 PM PDT, Kumar Kartikeya Dwivedi wrote:
> +		bpf_diag_report_irq_resource_state(env, env->insn_idx,
> +						   "IRQ flag restore mismatch",
> +						   bpf_diag_scratch_printf(env,
> +									   0,
> +									   "This IRQ flag was saved by %s IRQ kfuncs, but the restore call belongs to the %s IRQ kfunc family. Save and restore operations must use the same family.",
> +									   flag_kfunc,
> +									   used_kfunc),
> +						   "Restore the flag with the matching IRQ restore kfunc for the save operation that created it.",
> +						   env->cur_state->active_irq_id ? 1 : 0);

same concern as in the previous patch.

>  		return -EINVAL;
>  	}
>  
> @@ -1137,6 +1150,11 @@ static int unmark_stack_slot_irq_flag(struct bpf_verifier_env *env, struct bpf_r
>  
>  		verbose(env, "cannot restore irq state out of order, expected id=%d acquired at insn_idx=%d\n",
>  			env->cur_state->active_irq_id, insn_idx);
> +		bpf_diag_report_irq_resource_state(env, env->insn_idx,
> +						   "IRQ flag restore out of order",
> +						   "IRQ-disabled regions must be restored in last-in, first-out order, but this restore does not match the currently active IRQ flag.",
> +						   "Restore nested IRQ flags in the reverse order they were saved.",
> +						   env->cur_state->active_irq_id ? 1 : 0);
>  		return err;
>  	}
>  
> @@ -7258,11 +7276,19 @@ static int process_spin_lock(struct bpf_verifier_env *env, struct bpf_reg_state
>  			if (find_lock_state(env->cur_state, REF_TYPE_LOCK, 0, NULL)) {
>  				verbose(env,
>  					"Locking two bpf_spin_locks are not allowed\n");
> +				bpf_diag_report_resource_state(env, env->insn_idx,
> +							       "nested spin lock",
> +							       "This path already holds a bpf_spin_lock. The verifier allows only one regular BPF spin lock at a time.",
> +							       "Unlock the current bpf_spin_lock before taking another one.");
>  				return -EINVAL;
>  			}
>  		} else if (is_res_lock && cur->active_locks) {
>  			if (find_lock_state(env->cur_state, REF_TYPE_RES_LOCK | REF_TYPE_RES_LOCK_IRQ, reg->id, ptr)) {
>  				verbose(env, "Acquiring the same lock again, AA deadlock detected\n");
> +				bpf_diag_report_resource_state(env, env->insn_idx,
> +							       "recursive resource spin lock",
> +							       "This path already holds the same resource spin lock. Taking it again would deadlock.",
> +							       "Avoid reacquiring the same resource spin lock before it is unlocked.");
>  				return -EINVAL;
>  			}
>  		}
> @@ -7289,6 +7315,10 @@ static int process_spin_lock(struct bpf_verifier_env *env, struct bpf_reg_state
>  
>  		if (!cur->active_locks) {
>  			verbose(env, "%s_unlock without taking a lock\n", lock_str);
> +			bpf_diag_report_resource_state(env, env->insn_idx,
> +						       "unlock without lock",
> +						       "This unlock operation has no matching active lock on the current path.",
> +						       "Take the matching lock before this unlock, or remove the unmatched unlock path.");
>  			return -EINVAL;
>  		}
>  
> @@ -7300,14 +7330,26 @@ static int process_spin_lock(struct bpf_verifier_env *env, struct bpf_reg_state
>  			type = REF_TYPE_LOCK;
>  		if (!find_lock_state(cur, type, reg->id, ptr)) {
>  			verbose(env, "%s_unlock of different lock\n", lock_str);
> +			bpf_diag_report_resource_state(env, env->insn_idx,
> +						       "unlock of different lock",
> +						       "This unlock does not match any active lock with the same tracked identity on the current path.",
> +						       "Unlock the same lock object that was most recently acquired.");
>  			return -EINVAL;
>  		}
>  		if (reg->id != cur->active_lock_id || ptr != cur->active_lock_ptr) {
>  			verbose(env, "%s_unlock cannot be out of order\n", lock_str);
> +			bpf_diag_report_resource_state(env, env->insn_idx,
> +						       "unlock out of order",
> +						       "Locks must be released in last-in, first-out order, but this unlock does not match the currently active lock.",
> +						       "Release nested locks in the reverse order they were acquired.");
>  			return -EINVAL;
>  		}
>  		if (release_lock_state(env, type, reg->id, ptr)) {
>  			verbose(env, "%s_unlock of different lock\n", lock_str);
> +			bpf_diag_report_resource_state(env, env->insn_idx,
> +						       "unlock of different lock",
> +						       "The verifier could not release a lock state matching this unlock operation.",
> +						       "Pass the same lock object and lock kind that were used for the matching lock operation.");
>  			return -EINVAL;
>  		}
>  
> @@ -7473,6 +7515,10 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
>  		verbose(env,
>  			"%s expected pointer to stack or const struct bpf_dynptr\n",
>  			reg_arg_name(env, argno));
> +		bpf_diag_report_resource_state(env, insn_idx,
> +					       "invalid dynptr argument",
> +					       "A dynptr argument must be a pointer to a dynptr stack slot or a verifier-provided const struct bpf_dynptr.",
> +					       "Pass the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path.");
>  		return -EINVAL;
>  	}
>  
> @@ -7495,6 +7541,10 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
>  
>  		if (!is_dynptr_reg_valid_uninit(env, reg)) {
>  			verbose(env, "Dynptr has to be an uninitialized dynptr\n");
> +			bpf_diag_report_resource_state(env, insn_idx,
> +						       "dynptr is already initialized",
> +						       "This kfunc constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.",
> +						       "Use a fresh stack dynptr slot, or release/destroy the existing dynptr before reusing the slot.");
>  			return -EINVAL;
>  		}
>  
> @@ -7511,12 +7561,20 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
>  		/* For the reg->type == PTR_TO_STACK case, bpf_dynptr is never const */
>  		if (reg->type == CONST_PTR_TO_DYNPTR && (arg_type & OBJ_RELEASE)) {
>  			verbose(env, "CONST_PTR_TO_DYNPTR cannot be released\n");
> +			bpf_diag_report_resource_state(env, insn_idx,
> +						       "const dynptr release",
> +						       "This release operation was given a const dynptr. Const dynptr values are verifier-provided views and cannot be released by the program.",
> +						       "Release only mutable dynptrs that the program initialized or reserved.");
>  			return -EINVAL;
>  		}
>  
>  		if (!is_dynptr_reg_valid_init(env, reg)) {
>  			verbose(env, "Expected an initialized dynptr as %s\n",
>  				reg_arg_name(env, argno));
> +			bpf_diag_report_resource_state(env, insn_idx,
> +						       "uninitialized dynptr use",
> +						       "This operation requires an initialized dynptr, but the stack slot does not currently hold a valid dynptr on this path.",
> +						       "Initialize the dynptr on every path before this call, and avoid overwriting or releasing it before this use.");
>  			return -EINVAL;
>  		}
>  
> @@ -7526,6 +7584,10 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
>  				"Expected a dynptr of type %s as %s\n",
>  				dynptr_type_str(arg_to_dynptr_type(arg_type)),
>  				reg_arg_name(env, argno));
> +			bpf_diag_report_resource_state(env, insn_idx,
> +						       "wrong dynptr type",
> +						       "The dynptr is initialized, but it was created for a different backing object type than this operation accepts.",
> +						       "Use a dynptr constructor that matches this operation, or call an operation that accepts the dynptr's current type.");
>  			return -EINVAL;
>  		}
>  
> @@ -7594,6 +7656,10 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *
>  	if (reg->type != PTR_TO_STACK) {
>  		verbose(env, "%s expected pointer to an iterator on stack\n",
>  			reg_arg_name(env, argno));
> +		bpf_diag_report_resource_state(env, insn_idx,
> +					       "invalid iterator argument",
> +					       "Iterator state must live in verifier-tracked stack memory, but this argument is not a stack pointer.",
> +					       "Pass the address of a stack iterator object for iterator new, next, and destroy calls.");
>  		return -EINVAL;
>  	}
>  
> @@ -7607,6 +7673,10 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *
>  	if (btf_id < 0) {
>  		verbose(env, "expected valid iter pointer as %s\n",
>  			reg_arg_name(env, argno));
> +		bpf_diag_report_resource_state(env, insn_idx,
> +					       "invalid iterator type",
> +					       "The kfunc expects a recognized iterator state pointer, but this argument does not match a valid iterator type.",
> +					       "Pass the exact iterator state type expected by this kfunc.");
>  		return -EINVAL;
>  	}
>  	t = btf_type_by_id(meta->btf, btf_id);
> @@ -7617,6 +7687,10 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *
>  		if (!is_iter_reg_valid_uninit(env, reg, nr_slots)) {
>  			verbose(env, "expected uninitialized iter_%s as %s\n",
>  				iter_type_str(meta->btf, btf_id), reg_arg_name(env, argno));
> +			bpf_diag_report_resource_state(env, insn_idx,
> +						       "iterator is already initialized",
> +						       "Iterator creation requires an uninitialized iterator stack object, but this stack range already contains iterator state.",
> +						       "Use a fresh iterator stack slot, or destroy the existing iterator before reusing the slot.");

Maybe shorten bpf_diag_report_resource_state() name to bpf_diag() ?


  parent reply	other threads:[~2026-06-19 23:42 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-19 20:59 [PATCH bpf-next v2 00/17] Redesign Verification Errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 01/17] bpf: Add verifier diagnostics report helpers Kumar Kartikeya Dwivedi
2026-06-19 21:09   ` sashiko-bot
2026-06-19 20:59 ` [PATCH bpf-next v2 02/17] bpf: Add source and instruction diagnostic context Kumar Kartikeya Dwivedi
2026-06-19 21:46   ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 03/17] bpf: Add verifier diagnostic event log Kumar Kartikeya Dwivedi
2026-06-19 21:46   ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 04/17] bpf: Prune verifier diagnostics on backtracking Kumar Kartikeya Dwivedi
2026-06-19 21:46   ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 05/17] bpf: Track verifier register diagnostic events Kumar Kartikeya Dwivedi
2026-06-19 21:18   ` sashiko-bot
2026-06-19 23:35   ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 06/17] bpf: Track verifier reference " Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 07/17] bpf: Track verifier context " Kumar Kartikeya Dwivedi
2026-06-19 21:13   ` sashiko-bot
2026-06-19 21:19     ` Kumar Kartikeya Dwivedi
2026-06-19 21:46   ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 08/17] bpf: Report Register Type Safety errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 09/17] bpf: Report Memory Safety bounds errors Kumar Kartikeya Dwivedi
2026-06-19 21:46   ` bot+bpf-ci
2026-06-19 23:40   ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 10/17] bpf: Report Resource Lifetime reference leaks Kumar Kartikeya Dwivedi
2026-06-19 21:12   ` sashiko-bot
2026-06-19 23:42   ` Alexei Starovoitov [this message]
2026-06-19 20:59 ` [PATCH bpf-next v2 11/17] bpf: Report Call Type Safety argument errors Kumar Kartikeya Dwivedi
2026-06-19 21:47   ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 12/17] bpf: Report Execution Context Safety errors Kumar Kartikeya Dwivedi
2026-06-19 21:19   ` sashiko-bot
2026-06-19 23:44   ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 13/17] bpf: Report Program Structure CFG errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 14/17] bpf: Report Policy helper and kfunc errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 15/17] bpf: Report Verifier Limit errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 16/17] bpf: Report Verifier Internal errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 17/17] bpf: Gate verifier diagnostics on log level Kumar Kartikeya Dwivedi

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=DJDFA66W97OU.2VSS5QIMHBXCJ@gmail.com \
    --to=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=kernel-team@meta.com \
    --cc=kkd@meta.com \
    --cc=memxor@gmail.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