bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/2] bpf: Introduce bpf_in_interrupt kfunc
@ 2025-08-22 14:17 Leon Hwang
  2025-08-22 14:17 ` [PATCH bpf-next 1/2] " Leon Hwang
  2025-08-22 14:17 ` [PATCH bpf-next 2/2] selftests/bpf: Add case to test " Leon Hwang
  0 siblings, 2 replies; 4+ messages in thread
From: Leon Hwang @ 2025-08-22 14:17 UTC (permalink / raw)
  To: bpf
  Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
	leon.hwang, kernel-patches-bot

Filtering pid_tgid is meaningless when the current task is preempted by
an interrupt.

To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
programs to determine whether they are executing in interrupt context.

Internally, bpf_in_interrupt() is a thin wrapper around in_interrupt().
It is marked as fastcall function.

On x86_64, it is inlined for efficiency.

Leon Hwang (2):
  bpf: Introduce bpf_in_interrupt kfunc
  selftests/bpf: Add case to test bpf_in_interrupt kfunc

 kernel/bpf/helpers.c                    |  9 +++++++++
 kernel/bpf/verifier.c                   | 11 +++++++++++
 tools/testing/selftests/bpf/progs/irq.c |  7 +++++++
 3 files changed, 27 insertions(+)

--
2.50.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH bpf-next 1/2] bpf: Introduce bpf_in_interrupt kfunc
  2025-08-22 14:17 [PATCH bpf-next 0/2] bpf: Introduce bpf_in_interrupt kfunc Leon Hwang
@ 2025-08-22 14:17 ` Leon Hwang
  2025-08-23  8:24   ` kernel test robot
  2025-08-22 14:17 ` [PATCH bpf-next 2/2] selftests/bpf: Add case to test " Leon Hwang
  1 sibling, 1 reply; 4+ messages in thread
From: Leon Hwang @ 2025-08-22 14:17 UTC (permalink / raw)
  To: bpf
  Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
	leon.hwang, kernel-patches-bot

Filtering pid_tgid is meaningless when the current task is preempted by
an interrupt.

To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
programs to determine whether they are executing in interrupt context.

This enables programs to avoid applying pid_tgid filtering when running
in such contexts.

Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
 kernel/bpf/helpers.c  |  9 +++++++++
 kernel/bpf/verifier.c | 11 +++++++++++
 2 files changed, 20 insertions(+)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index cdffd74ddbe65..21e14697804e5 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -3714,6 +3714,14 @@ __bpf_kfunc int bpf_strstr(const char *s1__ign, const char *s2__ign)
 	return bpf_strnstr(s1__ign, s2__ign, XATTR_SIZE_MAX);
 }
 
+/**
+ * bpf_in_interrupt - Check whether it's in interrupt context
+ */
+__bpf_kfunc int bpf_in_interrupt(void)
+{
+	return in_interrupt();
+}
+
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(generic_btf_ids)
@@ -3754,6 +3762,7 @@ BTF_ID_FLAGS(func, bpf_throw)
 #ifdef CONFIG_BPF_EVENTS
 BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS)
 #endif
+BTF_ID_FLAGS(func, bpf_in_interrupt, KF_FASTCALL)
 BTF_KFUNCS_END(generic_btf_ids)
 
 static const struct btf_kfunc_id_set generic_kfunc_set = {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 4e47992361ea1..365d42140941d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12259,6 +12259,7 @@ enum special_kfunc_type {
 	KF_bpf_res_spin_lock_irqsave,
 	KF_bpf_res_spin_unlock_irqrestore,
 	KF___bpf_trap,
+	KF_bpf_in_interrupt,
 };
 
 BTF_ID_LIST(special_kfunc_list)
@@ -12327,6 +12328,7 @@ BTF_ID(func, bpf_res_spin_unlock)
 BTF_ID(func, bpf_res_spin_lock_irqsave)
 BTF_ID(func, bpf_res_spin_unlock_irqrestore)
 BTF_ID(func, __bpf_trap)
+BTF_ID(func, bpf_in_interrupt)
 
 static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta)
 {
@@ -21973,6 +21975,15 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 		   desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) {
 		insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
 		*cnt = 1;
+	} else if (desc->func_id == special_kfunc_list[KF_bpf_in_interrupt]) {
+#ifdef CONFIG_X86_64
+		insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
+		insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
+		insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0);
+		insn_buf[3] = BPF_ALU32_IMM(BPF_AND, BPF_REG_0, NMI_MASK | HARDIRQ_MASK |
+					    (IS_ENABLED(CONFIG_PREEMPT_RT) ? 0 : SOFTIRQ_MASK));
+		*cnt = 4;
+#endif
 	}
 
 	if (env->insn_aux_data[insn_idx].arg_prog) {
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH bpf-next 2/2] selftests/bpf: Add case to test bpf_in_interrupt kfunc
  2025-08-22 14:17 [PATCH bpf-next 0/2] bpf: Introduce bpf_in_interrupt kfunc Leon Hwang
  2025-08-22 14:17 ` [PATCH bpf-next 1/2] " Leon Hwang
@ 2025-08-22 14:17 ` Leon Hwang
  1 sibling, 0 replies; 4+ messages in thread
From: Leon Hwang @ 2025-08-22 14:17 UTC (permalink / raw)
  To: bpf
  Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
	leon.hwang, kernel-patches-bot

 cd tools/testing/selftests/bpf
 ./test_progs -t irq
 #143/29  irq/in_interrupt:OK
 #143     irq:OK
 Summary: 1/34 PASSED, 0 SKIPPED, 0 FAILED

Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
 tools/testing/selftests/bpf/progs/irq.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
index 74d912b22de90..65a796fd1d615 100644
--- a/tools/testing/selftests/bpf/progs/irq.c
+++ b/tools/testing/selftests/bpf/progs/irq.c
@@ -563,4 +563,11 @@ int irq_wrong_kfunc_class_2(struct __sk_buff *ctx)
 	return 0;
 }
 
+SEC("?tc")
+__success
+int in_interrupt(struct __sk_buff *ctx)
+{
+	return bpf_in_interrupt();
+}
+
 char _license[] SEC("license") = "GPL";
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Introduce bpf_in_interrupt kfunc
  2025-08-22 14:17 ` [PATCH bpf-next 1/2] " Leon Hwang
@ 2025-08-23  8:24   ` kernel test robot
  0 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2025-08-23  8:24 UTC (permalink / raw)
  To: Leon Hwang, bpf
  Cc: oe-kbuild-all, ast, andrii, daniel, martin.lau, eddyz87, song,
	yonghong.song, leon.hwang, kernel-patches-bot

Hi Leon,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Leon-Hwang/bpf-Introduce-bpf_in_interrupt-kfunc/20250822-222727
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20250822141722.25318-2-leon.hwang%40linux.dev
patch subject: [PATCH bpf-next 1/2] bpf: Introduce bpf_in_interrupt kfunc
config: um-allyesconfig (https://download.01.org/0day-ci/archive/20250823/202508231629.nrRSoIUD-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14+deb12u1) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250823/202508231629.nrRSoIUD-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508231629.nrRSoIUD-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from include/linux/bpf_verifier.h:9,
                    from kernel/bpf/verifier.c:13:
   kernel/bpf/verifier.c: In function 'fixup_kfunc_call':
>> kernel/bpf/verifier.c:21980:77: error: '__preempt_count' undeclared (first use in this function); did you mean 'preempt_count'?
   21980 |                 insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
         |                                                                             ^~~~~~~~~~~~~~~
   include/linux/filter.h:211:26: note: in definition of macro 'BPF_MOV64_IMM'
     211 |                 .imm   = IMM })
         |                          ^~~
   kernel/bpf/verifier.c:21980:77: note: each undeclared identifier is reported only once for each function it appears in
   21980 |                 insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
         |                                                                             ^~~~~~~~~~~~~~~
   include/linux/filter.h:211:26: note: in definition of macro 'BPF_MOV64_IMM'
     211 |                 .imm   = IMM })
         |                          ^~~


vim +21980 kernel/bpf/verifier.c

 21885	
 21886	static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 21887				    struct bpf_insn *insn_buf, int insn_idx, int *cnt)
 21888	{
 21889		const struct bpf_kfunc_desc *desc;
 21890	
 21891		if (!insn->imm) {
 21892			verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
 21893			return -EINVAL;
 21894		}
 21895	
 21896		*cnt = 0;
 21897	
 21898		/* insn->imm has the btf func_id. Replace it with an offset relative to
 21899		 * __bpf_call_base, unless the JIT needs to call functions that are
 21900		 * further than 32 bits away (bpf_jit_supports_far_kfunc_call()).
 21901		 */
 21902		desc = find_kfunc_desc(env->prog, insn->imm, insn->off);
 21903		if (!desc) {
 21904			verifier_bug(env, "kernel function descriptor not found for func_id %u",
 21905				     insn->imm);
 21906			return -EFAULT;
 21907		}
 21908	
 21909		if (!bpf_jit_supports_far_kfunc_call())
 21910			insn->imm = BPF_CALL_IMM(desc->addr);
 21911		if (insn->off)
 21912			return 0;
 21913		if (desc->func_id == special_kfunc_list[KF_bpf_obj_new_impl] ||
 21914		    desc->func_id == special_kfunc_list[KF_bpf_percpu_obj_new_impl]) {
 21915			struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta;
 21916			struct bpf_insn addr[2] = { BPF_LD_IMM64(BPF_REG_2, (long)kptr_struct_meta) };
 21917			u64 obj_new_size = env->insn_aux_data[insn_idx].obj_new_size;
 21918	
 21919			if (desc->func_id == special_kfunc_list[KF_bpf_percpu_obj_new_impl] && kptr_struct_meta) {
 21920				verifier_bug(env, "NULL kptr_struct_meta expected at insn_idx %d",
 21921					     insn_idx);
 21922				return -EFAULT;
 21923			}
 21924	
 21925			insn_buf[0] = BPF_MOV64_IMM(BPF_REG_1, obj_new_size);
 21926			insn_buf[1] = addr[0];
 21927			insn_buf[2] = addr[1];
 21928			insn_buf[3] = *insn;
 21929			*cnt = 4;
 21930		} else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl] ||
 21931			   desc->func_id == special_kfunc_list[KF_bpf_percpu_obj_drop_impl] ||
 21932			   desc->func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]) {
 21933			struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta;
 21934			struct bpf_insn addr[2] = { BPF_LD_IMM64(BPF_REG_2, (long)kptr_struct_meta) };
 21935	
 21936			if (desc->func_id == special_kfunc_list[KF_bpf_percpu_obj_drop_impl] && kptr_struct_meta) {
 21937				verifier_bug(env, "NULL kptr_struct_meta expected at insn_idx %d",
 21938					     insn_idx);
 21939				return -EFAULT;
 21940			}
 21941	
 21942			if (desc->func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl] &&
 21943			    !kptr_struct_meta) {
 21944				verifier_bug(env, "kptr_struct_meta expected at insn_idx %d",
 21945					     insn_idx);
 21946				return -EFAULT;
 21947			}
 21948	
 21949			insn_buf[0] = addr[0];
 21950			insn_buf[1] = addr[1];
 21951			insn_buf[2] = *insn;
 21952			*cnt = 3;
 21953		} else if (desc->func_id == special_kfunc_list[KF_bpf_list_push_back_impl] ||
 21954			   desc->func_id == special_kfunc_list[KF_bpf_list_push_front_impl] ||
 21955			   desc->func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) {
 21956			struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta;
 21957			int struct_meta_reg = BPF_REG_3;
 21958			int node_offset_reg = BPF_REG_4;
 21959	
 21960			/* rbtree_add has extra 'less' arg, so args-to-fixup are in diff regs */
 21961			if (desc->func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) {
 21962				struct_meta_reg = BPF_REG_4;
 21963				node_offset_reg = BPF_REG_5;
 21964			}
 21965	
 21966			if (!kptr_struct_meta) {
 21967				verifier_bug(env, "kptr_struct_meta expected at insn_idx %d",
 21968					     insn_idx);
 21969				return -EFAULT;
 21970			}
 21971	
 21972			__fixup_collection_insert_kfunc(&env->insn_aux_data[insn_idx], struct_meta_reg,
 21973							node_offset_reg, insn, insn_buf, cnt);
 21974		} else if (desc->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
 21975			   desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) {
 21976			insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
 21977			*cnt = 1;
 21978		} else if (desc->func_id == special_kfunc_list[KF_bpf_in_interrupt]) {
 21979	#ifdef CONFIG_X86_64
 21980			insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
 21981			insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
 21982			insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0);
 21983			insn_buf[3] = BPF_ALU32_IMM(BPF_AND, BPF_REG_0, NMI_MASK | HARDIRQ_MASK |
 21984						    (IS_ENABLED(CONFIG_PREEMPT_RT) ? 0 : SOFTIRQ_MASK));
 21985			*cnt = 4;
 21986	#endif
 21987		}
 21988	
 21989		if (env->insn_aux_data[insn_idx].arg_prog) {
 21990			u32 regno = env->insn_aux_data[insn_idx].arg_prog;
 21991			struct bpf_insn ld_addrs[2] = { BPF_LD_IMM64(regno, (long)env->prog->aux) };
 21992			int idx = *cnt;
 21993	
 21994			insn_buf[idx++] = ld_addrs[0];
 21995			insn_buf[idx++] = ld_addrs[1];
 21996			insn_buf[idx++] = *insn;
 21997			*cnt = idx;
 21998		}
 21999		return 0;
 22000	}
 22001	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-08-23  8:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-22 14:17 [PATCH bpf-next 0/2] bpf: Introduce bpf_in_interrupt kfunc Leon Hwang
2025-08-22 14:17 ` [PATCH bpf-next 1/2] " Leon Hwang
2025-08-23  8:24   ` kernel test robot
2025-08-22 14:17 ` [PATCH bpf-next 2/2] selftests/bpf: Add case to test " Leon Hwang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).