* [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).