From nobody Sat Oct 3 03:53:13 2026 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 772EB47FAF2; Wed, 5 Aug 2026 15:34:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785944052; cv=none; b=aAPBIKx+J8cR109AK3xf0kdWBF2lNbQpdfsEY/WDEKATp/1pCHYyw3TE03sNRJ8KZH1e5h7epVum4Jo6t48lhvw8nYjpWHFp5tuGyxBYQyGWPzfQt6fsqW2NgnXTcer5S9PF7+4h46qB9PGazTuKU1wQr1HW/owWWWTkpC4y2gQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785944052; c=relaxed/simple; bh=5QGg8UA6TP6BiR80nmMNPD+9XP0RRFAEKZsYNq+PShI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=u3M2WJ5o0Ynu0+EMTo8XyeCU5797uLnDOEJ272ku68U6IlfgH/nKQ8UDmRXYzkKIBlh5hMpQTTehD3P3MPbam4quzCaF1vpFIsoDjL8zwyP9VxT0+9Ah3r2OqBIppsVEBFSwVdPPTvZSvefawGYgVkw8Ei5jBsU1c2EzNCEfc3o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=slDBi+5+; arc=none smtp.client-ip=91.218.175.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="slDBi+5+" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1785944039; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=htN/R7/vpvjJoj57m1JcFVCCQB3lZ4Dh9rkDr6cbV4k=; b=slDBi+5+gotQFoyTbh6AFITlB5cTmV9fuhq7RoT6Fpqi3I0AymEJxofg4tke/BeUYogbSZ w3r+PNeAJ/ulwtRneVutsoRd7FY8LML8XLlV8k/RkNvnWbn83aJ0YD/81IIn7eLxhAMbsU zzI+yo/btDFe7qoxmjoOe7rNv1PdkoY= From: Kaitao Cheng To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Eduard Zingerman , Kumar Kartikeya Dwivedi , Martin KaFai Lau , Song Liu , Yonghong Song , Jiri Olsa , Emil Tsalapatis , Ihor Solodrai , John Fastabend , Shuah Khan , Leon Hwang Cc: bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Kaitao Cheng Subject: [PATCH bpf-next v2 1/3] bpf: Add KF_SPINLOCK_SAFE flag for kfuncs under bpf_spin_lock Date: Wed, 5 Aug 2026 23:33:38 +0800 Message-ID: <20260805153340.34776-2-kaitao.cheng@linux.dev> In-Reply-To: <20260805153340.34776-1-kaitao.cheng@linux.dev> References: <20260805153340.34776-1-kaitao.cheng@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Introduce the KF_SPINLOCK_SAFE kfunc metadata flag in BTF so kfuncs may be explicitly marked as safe to call while holding bpf_spin_lock. Allow kfuncs defined in kernel modules to be marked with KF_SPINLOCK_SAFE. Example: BTF_ID_FLAGS(func, $kfunc_name, KF_SPINLOCK_SAFE) Signed-off-by: Kaitao Cheng Acked-by: Leon Hwang --- include/linux/btf.h | 1 + kernel/bpf/verifier.c | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index c09b7994de4e..3f5255d095a2 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -79,6 +79,7 @@ #define KF_ARENA_ARG1 (1 << 14) /* kfunc takes an arena pointer as its f= irst argument */ #define KF_ARENA_ARG2 (1 << 15) /* kfunc takes an arena pointer as its s= econd argument */ #define KF_IMPLICIT_ARGS (1 << 16) /* kfunc has implicit arguments supplie= d by the verifier */ +#define KF_SPINLOCK_SAFE (1 << 17) /* kfunc is allowed inside bpf_spin_loc= k-ed region */ =20 /* * Tag marking a kernel function as a kfunc. This is meant to minimize the diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b274004fccfd..9c1f8d552655 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -11832,11 +11832,21 @@ static bool is_bpf_stream_kfunc(u32 btf_id) btf_id =3D=3D special_kfunc_list[KF_bpf_stream_print_stack]; } =20 -static bool kfunc_spin_allowed(u32 btf_id) +static bool kfunc_spin_allowed(struct bpf_verifier_env *env, s32 func_id, = s16 offset) { - return is_bpf_graph_api_kfunc(btf_id) || is_bpf_iter_num_api_kfunc(btf_id= ) || - is_bpf_res_spin_lock_kfunc(btf_id) || is_bpf_arena_kfunc(btf_id) || - is_bpf_stream_kfunc(btf_id); + struct bpf_kfunc_meta kfunc; + int err; + + if (is_bpf_graph_api_kfunc(func_id) || is_bpf_iter_num_api_kfunc(func_id)= || + is_bpf_res_spin_lock_kfunc(func_id) || is_bpf_arena_kfunc(func_id) || + is_bpf_stream_kfunc(func_id)) + return true; + + err =3D fetch_kfunc_meta(env, func_id, offset, &kfunc); + if (err || !kfunc.flags) + return false; + + return *kfunc.flags & KF_SPINLOCK_SAFE; } =20 static bool is_sync_callback_calling_kfunc(u32 btf_id) @@ -17415,7 +17425,7 @@ static int do_check_insn(struct bpf_verifier_env *e= nv, bool *do_print_state) insn->imm !=3D BPF_FUNC_spin_unlock && insn->imm !=3D BPF_FUNC_kptr_xchg) || (insn->src_reg =3D=3D BPF_PSEUDO_KFUNC_CALL && - (insn->off !=3D 0 || !kfunc_spin_allowed(insn->imm)))) { + !kfunc_spin_allowed(env, insn->imm, insn->off))) { verbose(env, "function calls are not allowed while holding a lock\n"); return -EINVAL; --=20 2.50.1 (Apple Git-155) From nobody Sat Oct 3 03:53:13 2026 Received: from out-170.mta0.migadu.com (out-170.mta0.migadu.com [91.218.175.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7E5A847F2C2 for ; Wed, 5 Aug 2026 15:34:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785944060; cv=none; b=QN25dbuPR+RMsqWgS1F56ERZ+JMxuyqWzi0opDVFwDLXqPAZMIPAlYzLf6G3FZ0dhnbPewd8aXiND+Y0mjVPvEtU0WKYc71Ra6b91MmboHvWBmyFQ4C6ojEnJ5GvBTRlML0jR4PmhdzLZmJTqaHA3y2G5hCZqeAbZM7baKbn0qs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785944060; c=relaxed/simple; bh=Fq9mPhF+x4kABBj3fAZkbuJ1hBAgDuPfZcD+bGPvZNI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YdoRr7V9BZT8RoPeLVcrMbdM4eF12QpIlzA+xQ2nwpnTesEHK3pcHvG6alfC1BEPTL6VO4b55iRjqpmQ9LWnb14V0PG3Q4+E3H6B6ooDI0ZJZ+BeYte6tNnKKRdQZz0hmni6BtQfV/NEjR7dvyobb7rdamUtpnw0i8VeNucMWMA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=G/LtLcDR; arc=none smtp.client-ip=91.218.175.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="G/LtLcDR" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1785944045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NyCUO76kvyNGTAYi37CSbvCLeWxsrL1T0JqZ1cD6Rbc=; b=G/LtLcDRu7v9/sVoV/lpFoKigUzmmdYA/rDC4yNlwENcO3eHQPdEIxaALDl/6vqYgVF02T epXATG558Oj7JtpAORycqVp2rnEremLg0gzDzIV2/CzK3nXOFRtLK9EUHXnu8RN9cSNmII ZFtxWKWPvN+4SNTmGdySiCloEgopE7M= From: Kaitao Cheng To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Eduard Zingerman , Kumar Kartikeya Dwivedi , Martin KaFai Lau , Song Liu , Yonghong Song , Jiri Olsa , Emil Tsalapatis , Ihor Solodrai , John Fastabend , Shuah Khan , Leon Hwang Cc: bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Kaitao Cheng Subject: [PATCH bpf-next v2 2/3] bpf: Mark existing lock-safe kfuncs with KF_SPINLOCK_SAFE Date: Wed, 5 Aug 2026 23:33:39 +0800 Message-ID: <20260805153340.34776-3-kaitao.cheng@linux.dev> In-Reply-To: <20260805153340.34776-1-kaitao.cheng@linux.dev> References: <20260805153340.34776-1-kaitao.cheng@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng The verifier currently keeps a hard-coded list of kfuncs that may be called while holding a bpf_spin_lock. With KF_SPINLOCK_SAFE available, retaining this list creates two sources of truth and requires verifier changes whenever another lock-safe kfunc is added. Mark every kfunc currently accepted by kfunc_spin_allowed() with KF_SPINLOCK_SAFE. This covers the graph, numeric iterator, resource spin lock, arena, and stream kfuncs. Remove the obsolete category checks and make kfunc_spin_allowed() rely solely on the kfunc registration metadata. This preserves the behavior of existing kfuncs while using the same mechanism for built-in and module kfuncs. Signed-off-by: Kaitao Cheng Acked-by: Leon Hwang --- kernel/bpf/arena.c | 6 ++--- kernel/bpf/helpers.c | 56 +++++++++++++++++++++-------------------- kernel/bpf/rqspinlock.c | 8 +++--- kernel/bpf/verifier.c | 32 ----------------------- 4 files changed, 36 insertions(+), 66 deletions(-) diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c index 555ee2531ef9..7b6847200b43 100644 --- a/kernel/bpf/arena.c +++ b/kernel/bpf/arena.c @@ -1118,9 +1118,9 @@ __bpf_kfunc int bpf_arena_reserve_pages(void *p__map,= void *ptr__ign, u32 page_c __bpf_kfunc_end_defs(); =20 BTF_KFUNCS_START(arena_kfuncs) -BTF_ID_FLAGS(func, bpf_arena_alloc_pages, KF_ARENA_RET | KF_ARENA_ARG2) -BTF_ID_FLAGS(func, bpf_arena_free_pages, KF_ARENA_ARG2) -BTF_ID_FLAGS(func, bpf_arena_reserve_pages, KF_ARENA_ARG2) +BTF_ID_FLAGS(func, bpf_arena_alloc_pages, KF_ARENA_RET | KF_ARENA_ARG2 | K= F_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_arena_free_pages, KF_ARENA_ARG2 | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_arena_reserve_pages, KF_ARENA_ARG2 | KF_SPINLOCK_SA= FE) BTF_KFUNCS_END(arena_kfuncs) =20 static const struct btf_kfunc_id_set common_kfunc_set =3D { diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 4709a5ad0474..6388b6b23e49 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -4812,30 +4812,32 @@ BTF_ID_FLAGS(func, bpf_obj_drop, KF_RELEASE | KF_IM= PLICIT_ARGS) BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) BTF_ID_FLAGS(func, bpf_percpu_obj_drop, KF_RELEASE | KF_IMPLICIT_ARGS) BTF_ID_FLAGS(func, bpf_percpu_obj_drop_impl, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_refcount_acquire, KF_ACQUIRE | KF_RET_NULL | KF_RCU= | KF_IMPLICIT_ARGS) -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL | K= F_RCU) -BTF_ID_FLAGS(func, bpf_list_push_front, KF_IMPLICIT_ARGS) -BTF_ID_FLAGS(func, bpf_list_push_front_impl) -BTF_ID_FLAGS(func, bpf_list_push_back, KF_IMPLICIT_ARGS) -BTF_ID_FLAGS(func, bpf_list_push_back_impl) -BTF_ID_FLAGS(func, bpf_list_add, KF_IMPLICIT_ARGS) -BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_list_del, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_list_front, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_list_back, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_list_is_first) -BTF_ID_FLAGS(func, bpf_list_is_last) -BTF_ID_FLAGS(func, bpf_list_empty) +BTF_ID_FLAGS(func, bpf_refcount_acquire, + KF_ACQUIRE | KF_RET_NULL | KF_RCU | KF_IMPLICIT_ARGS | KF_SPINLOCK_S= AFE) +BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, + KF_ACQUIRE | KF_RET_NULL | KF_RCU | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_push_front, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAF= E) +BTF_ID_FLAGS(func, bpf_list_push_front_impl, KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_push_back, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_push_back_impl, KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_add, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL | KF_SPINL= OCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL | KF_SPINLO= CK_SAFE) +BTF_ID_FLAGS(func, bpf_list_del, KF_ACQUIRE | KF_RET_NULL | KF_SPINLOCK_SA= FE) +BTF_ID_FLAGS(func, bpf_list_front, KF_RET_NULL | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_back, KF_RET_NULL | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_is_first, KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_is_last, KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_list_empty, KF_SPINLOCK_SAFE) BTF_ID_FLAGS(func, bpf_task_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_task_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_rbtree_remove, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_rbtree_add, KF_IMPLICIT_ARGS) -BTF_ID_FLAGS(func, bpf_rbtree_add_impl) -BTF_ID_FLAGS(func, bpf_rbtree_first, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_rbtree_root, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_rbtree_left, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_rbtree_right, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_rbtree_remove, KF_ACQUIRE | KF_RET_NULL | KF_SPINLO= CK_SAFE) +BTF_ID_FLAGS(func, bpf_rbtree_add, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_rbtree_add_impl, KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_rbtree_first, KF_RET_NULL | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_rbtree_root, KF_RET_NULL | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_rbtree_left, KF_RET_NULL | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_rbtree_right, KF_RET_NULL | KF_SPINLOCK_SAFE) =20 #ifdef CONFIG_CGROUPS BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) @@ -4885,9 +4887,9 @@ BTF_ID_FLAGS(func, bpf_rcu_read_lock) BTF_ID_FLAGS(func, bpf_rcu_read_unlock) BTF_ID_FLAGS(func, bpf_dynptr_slice, KF_RET_NULL) BTF_ID_FLAGS(func, bpf_dynptr_slice_rdwr, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_iter_num_new, KF_ITER_NEW) -BTF_ID_FLAGS(func, bpf_iter_num_next, KF_ITER_NEXT | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY) +BTF_ID_FLAGS(func, bpf_iter_num_new, KF_ITER_NEW | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_iter_num_next, KF_ITER_NEXT | KF_RET_NULL | KF_SPIN= LOCK_SAFE) +BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY | KF_SPINLOCK_SAF= E) BTF_ID_FLAGS(func, bpf_iter_task_vma_new, KF_ITER_NEW | KF_RCU) BTF_ID_FLAGS(func, bpf_iter_task_vma_next, KF_ITER_NEXT | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_iter_task_vma_destroy, KF_ITER_DESTROY) @@ -4962,8 +4964,8 @@ BTF_ID_FLAGS(func, bpf_strncasestr); #if defined(CONFIG_BPF_LSM) && defined(CONFIG_CGROUPS) BTF_ID_FLAGS(func, bpf_cgroup_read_xattr, KF_RCU) #endif -BTF_ID_FLAGS(func, bpf_stream_vprintk, KF_IMPLICIT_ARGS) -BTF_ID_FLAGS(func, bpf_stream_print_stack, KF_IMPLICIT_ARGS) +BTF_ID_FLAGS(func, bpf_stream_vprintk, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_stream_print_stack, KF_IMPLICIT_ARGS | KF_SPINLOCK_= SAFE) BTF_ID_FLAGS(func, bpf_task_work_schedule_signal, KF_IMPLICIT_ARGS) BTF_ID_FLAGS(func, bpf_task_work_schedule_resume, KF_IMPLICIT_ARGS) BTF_ID_FLAGS(func, bpf_dynptr_from_file) diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c index e4e338cdb437..e527cb425cf4 100644 --- a/kernel/bpf/rqspinlock.c +++ b/kernel/bpf/rqspinlock.c @@ -744,10 +744,10 @@ __bpf_kfunc void bpf_res_spin_unlock_irqrestore(struc= t bpf_res_spin_lock *lock, __bpf_kfunc_end_defs(); =20 BTF_KFUNCS_START(rqspinlock_kfunc_ids) -BTF_ID_FLAGS(func, bpf_res_spin_lock, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_res_spin_unlock) -BTF_ID_FLAGS(func, bpf_res_spin_lock_irqsave, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_res_spin_unlock_irqrestore) +BTF_ID_FLAGS(func, bpf_res_spin_lock, KF_RET_NULL | KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_res_spin_unlock, KF_SPINLOCK_SAFE) +BTF_ID_FLAGS(func, bpf_res_spin_lock_irqsave, KF_RET_NULL | KF_SPINLOCK_SA= FE) +BTF_ID_FLAGS(func, bpf_res_spin_unlock_irqrestore, KF_SPINLOCK_SAFE) BTF_KFUNCS_END(rqspinlock_kfunc_ids) =20 static const struct btf_kfunc_id_set rqspinlock_kfunc_set =3D { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9c1f8d552655..7c1edcae293a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -11797,20 +11797,6 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id) btf_id =3D=3D special_kfunc_list[KF_bpf_rbtree_right]; } =20 -static bool is_bpf_iter_num_api_kfunc(u32 btf_id) -{ - return btf_id =3D=3D special_kfunc_list[KF_bpf_iter_num_new] || - btf_id =3D=3D special_kfunc_list[KF_bpf_iter_num_next] || - btf_id =3D=3D special_kfunc_list[KF_bpf_iter_num_destroy]; -} - -static bool is_bpf_graph_api_kfunc(u32 btf_id) -{ - return is_bpf_list_api_kfunc(btf_id) || - is_bpf_rbtree_api_kfunc(btf_id) || - is_bpf_refcount_acquire_kfunc(btf_id); -} - static bool is_bpf_res_spin_lock_kfunc(u32 btf_id) { return btf_id =3D=3D special_kfunc_list[KF_bpf_res_spin_lock] || @@ -11819,29 +11805,11 @@ static bool is_bpf_res_spin_lock_kfunc(u32 btf_id) btf_id =3D=3D special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore= ]; } =20 -static bool is_bpf_arena_kfunc(u32 btf_id) -{ - return btf_id =3D=3D special_kfunc_list[KF_bpf_arena_alloc_pages] || - btf_id =3D=3D special_kfunc_list[KF_bpf_arena_free_pages] || - btf_id =3D=3D special_kfunc_list[KF_bpf_arena_reserve_pages]; -} - -static bool is_bpf_stream_kfunc(u32 btf_id) -{ - return btf_id =3D=3D special_kfunc_list[KF_bpf_stream_vprintk] || - btf_id =3D=3D special_kfunc_list[KF_bpf_stream_print_stack]; -} - static bool kfunc_spin_allowed(struct bpf_verifier_env *env, s32 func_id, = s16 offset) { struct bpf_kfunc_meta kfunc; int err; =20 - if (is_bpf_graph_api_kfunc(func_id) || is_bpf_iter_num_api_kfunc(func_id)= || - is_bpf_res_spin_lock_kfunc(func_id) || is_bpf_arena_kfunc(func_id) || - is_bpf_stream_kfunc(func_id)) - return true; - err =3D fetch_kfunc_meta(env, func_id, offset, &kfunc); if (err || !kfunc.flags) return false; --=20 2.50.1 (Apple Git-155) From nobody Sat Oct 3 03:53:13 2026 Received: from out-186.mta0.migadu.com (out-186.mta0.migadu.com [91.218.175.186]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5CD7C47F2CD for ; Wed, 5 Aug 2026 15:34:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.186 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785944068; cv=none; b=KcgzFW5zIi7q+deijAk4ipd46O1jyogAWowD3MMcpWHoGuOsSdakrb2Yt4YGnSUCbyS8O78edr1ZoDxRh6JrJJAG/beKrudqy28IpaIHnlP6f1F5/FLW+Bml+/UqqKwic52z5cCYaMno+tDk9itKWezmGgiIUTXmmdccYF65CCs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785944068; c=relaxed/simple; bh=Zs5H7cMZtG2P7oyTZ5Hzw070uiL1GvEuUmtkmYsw1Co=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mjmvw8yFSvawsmE3Br9DH74bc4NNtE+7SUfj9pLhcfzFWvedsFJrA4SjwpIYdLVY0A0JYmEybQ9CacmZcgaPiypZERaTHKHmMiJ5xwOxHJJbHPPADMdZ36T8aX4T9XLwqLe4g2XzIhB/D5AvDo9Bi82TU1pINkn0NQ6QJmTl+8g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=S6pqvAhI; arc=none smtp.client-ip=91.218.175.186 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="S6pqvAhI" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1785944051; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WnTpfffi4HdZULUYUzgBmCgy+bFF8M6Arvi3UvMRAbA=; b=S6pqvAhIwMTsIqnNLnQF1Ivu93hQYpIr+BbFAlZ5ZJS1XnW13skP/I/vcoFR0jQIGL64D4 1uQft4YPgu3MhSanztPn/e0lcl2iBmIuOHPK0PfMbMFZZUTjErRbMWk1EO2ls1udx7lG/u EE5UL12Bsxi+3I0gXE0iBDq2OjOpclk= From: Kaitao Cheng To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Eduard Zingerman , Kumar Kartikeya Dwivedi , Martin KaFai Lau , Song Liu , Yonghong Song , Jiri Olsa , Emil Tsalapatis , Ihor Solodrai , John Fastabend , Shuah Khan , Leon Hwang Cc: bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Kaitao Cheng Subject: [PATCH bpf-next v2 3/3] selftests/bpf: Test module kfunc calls under spin lock Date: Wed, 5 Aug 2026 23:33:40 +0800 Message-ID: <20260805153340.34776-4-kaitao.cheng@linux.dev> In-Reply-To: <20260805153340.34776-1-kaitao.cheng@linux.dev> References: <20260805153340.34776-1-kaitao.cheng@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng The verifier uses kfunc registration flags to decide whether a kfunc may be called while a BPF program holds a bpf_spin_lock. Mark bpf_testmod_test_mod_kfunc() as KF_SPINLOCK_SAFE and verify that it can be called while holding a bpf_spin_lock. Also attempt to call the unmarked bpf_kfunc_trigger_ctx_check() under the lock and verify that the program is rejected. Signed-off-by: Kaitao Cheng Acked-by: Leon Hwang --- tools/testing/selftests/bpf/prog_tests/kfunc_call.c | 2 ++ tools/testing/selftests/bpf/progs/kfunc_call_fail.c | 12 ++++++++++++ tools/testing/selftests/bpf/progs/kfunc_call_test.c | 12 ++++++++++++ tools/testing/selftests/bpf/test_kmods/bpf_testmod.c | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/te= sting/selftests/bpf/prog_tests/kfunc_call.c index 7af5560f2a08..2b39cc1b09f9 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c @@ -71,8 +71,10 @@ static struct kfunc_test_params kfunc_tests[] =3D { TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"), TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function doe= s not return PTR_TO_BTF_ID"), TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 expected pointe= r to ctx, but got scalar"), + TC_FAIL(kfunc_call_test_spin_lock_unsafe, 0, "function calls are not allo= wed while holding a lock"), =20 /* success cases */ + TC_TEST(kfunc_call_test_spin_lock_safe, 0), TC_TEST(kfunc_call_test1, 12), TC_TEST(kfunc_call_test2, 3), TC_TEST(kfunc_call_test4, -1234), diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c b/tools/te= sting/selftests/bpf/progs/kfunc_call_fail.c index 64b6a0b0ab1c..7e93f7fb1329 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c @@ -4,6 +4,18 @@ #include #include "../test_kmods/bpf_testmod_kfunc.h" =20 +static struct bpf_spin_lock kfunc_call_lock SEC(".data.A"); + +SEC("?tc") +int kfunc_call_test_spin_lock_unsafe(struct __sk_buff *skb) +{ + bpf_spin_lock(&kfunc_call_lock); + bpf_kfunc_trigger_ctx_check(); + bpf_spin_unlock(&kfunc_call_lock); + + return 0; +} + struct syscall_test_args { __u8 data[16]; size_t size; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test.c b/tools/te= sting/selftests/bpf/progs/kfunc_call_test.c index 5edc51564f71..8e6560c31e78 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test.c @@ -5,6 +5,18 @@ #include "bpf_misc.h" #include "../test_kmods/bpf_testmod_kfunc.h" =20 +static struct bpf_spin_lock kfunc_call_lock SEC(".data.A"); + +SEC("tc") +int kfunc_call_test_spin_lock_safe(struct __sk_buff *skb) +{ + bpf_spin_lock(&kfunc_call_lock); + bpf_testmod_test_mod_kfunc(42); + bpf_spin_unlock(&kfunc_call_lock); + + return 0; +} + SEC("tc") int kfunc_call_test5(struct __sk_buff *skb) { diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/t= esting/selftests/bpf/test_kmods/bpf_testmod.c index eb0f9b5e18d8..0585794606ed 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c @@ -1384,7 +1384,7 @@ __bpf_kfunc void bpf_kfunc_trigger_ctx_check(void) } =20 BTF_KFUNCS_START(bpf_testmod_check_kfunc_ids) -BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc) +BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc, KF_SPINLOCK_SAFE) BTF_ID_FLAGS(func, bpf_kfunc_call_test1) BTF_ID_FLAGS(func, bpf_kfunc_call_test2) BTF_ID_FLAGS(func, bpf_kfunc_call_test3) --=20 2.50.1 (Apple Git-155)