All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag
@ 2026-09-10 14:21 Daniel Borkmann
  2026-09-10 14:21 ` [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory Daniel Borkmann
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Daniel Borkmann @ 2026-09-10 14:21 UTC (permalink / raw)
  To: ast; +Cc: memxor, eddyz87, info, bpf

Tracing related BPF helpers e.g. under bpf_base_func_proto() are gated
behind CAP_PERFMON. However, the same is currently not true for kfuncs
and they are accessible via plain CAP_BPF. Add a new KF_PERFMON flag
which can be used such that check_kfunc_call() ensures env->allow_ptr_leaks
is permitted. This follows similar pattern to existing KF_DESTRUCTIVE flag.

The rejection returns -EPERM to match the other CAP_PERFMON gates in the
verifier, that is, check_ptr_to_btf_access() and check_ptr_to_map_access(),
which report the very same policy to user space.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 Documentation/bpf/kfuncs.rst | 10 ++++++++++
 include/linux/btf.h          |  1 +
 kernel/bpf/verifier.c        | 15 +++++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst
index 85f73e0bbd0f..6691fe8a32c3 100644
--- a/Documentation/bpf/kfuncs.rst
+++ b/Documentation/bpf/kfuncs.rst
@@ -486,6 +486,16 @@ Example usage in BPF program:
 	/* note that the last argument is omitted */
         bpf_task_work_schedule_signal(task, &work->tw, &arrmap, task_work_callback);
 
+2.5.10 KF_PERFMON flag
+----------------------
+
+The KF_PERFMON flag is used for kfuncs that can expose kernel memory or kernel
+addresses to the BPF program, for example by reading through a pointer that the
+verifier does not check. Calling such a kfunc requires CAP_PERFMON, or
+CAP_SYS_ADMIN, in the same way that the equivalent BPF helpers are gated in
+bpf_base_func_proto(). A program loaded with CAP_BPF alone is rejected at load
+time.
+
 2.6 Registering the kfuncs
 --------------------------
 
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 89d5a5c4f117..7c62ea17b116 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -80,6 +80,7 @@
 #define KF_ARENA_ARG2   (1 << 15) /* kfunc takes an arena pointer as its second argument */
 #define KF_IMPLICIT_ARGS (1 << 16) /* kfunc has implicit arguments supplied by the verifier */
 #define KF_SPINLOCK_SAFE (1 << 17) /* kfunc is allowed inside bpf_spin_lock-ed region */
+#define KF_PERFMON      (1 << 18) /* kfunc requires CAP_PERFMON */
 
 /*
  * 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 45234e2fbee6..5d61e74865a8 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11356,6 +11356,11 @@ static bool is_kfunc_destructive(struct bpf_call_arg_meta *meta)
 	return meta->kfunc_flags & KF_DESTRUCTIVE;
 }
 
+static bool is_kfunc_perfmon(struct bpf_call_arg_meta *meta)
+{
+	return meta->kfunc_flags & KF_PERFMON;
+}
+
 static bool is_kfunc_rcu(struct bpf_call_arg_meta *meta)
 {
 	return meta->kfunc_flags & KF_RCU;
@@ -13834,6 +13839,16 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 		return -EACCES;
 	}
 
+	if (is_kfunc_perfmon(&meta) && !env->allow_ptr_leaks) {
+		verbose(env, "%s is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
+			func_name);
+		operation = bpf_diag_fmt(env, "kfunc %s", func_name);
+		bpf_diag_policy(
+			env, insn_idx, operation, "the kfunc requires CAP_PERFMON",
+			"Load the program with CAP_PERFMON, or avoid the kfunc.");
+		return -EPERM;
+	}
+
 	sleepable = bpf_is_kfunc_sleepable(&meta);
 	if (sleepable && !in_sleepable(env)) {
 		verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name);
-- 
2.43.0


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

* [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory
  2026-09-10 14:21 [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Daniel Borkmann
@ 2026-09-10 14:21 ` Daniel Borkmann
  2026-09-10 15:10   ` bot+bpf-ci
  2026-09-10 15:41   ` Alexei Starovoitov
  2026-09-10 14:21 ` [PATCH bpf 3/4] bpf: Require CAP_PERFMON for untrusted read-only memory reads Daniel Borkmann
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 12+ messages in thread
From: Daniel Borkmann @ 2026-09-10 14:21 UTC (permalink / raw)
  To: ast; +Cc: memxor, eddyz87, info, bpf

Mark fault-safe probe reading kfuncs as KF_PERFMON, similarly as we do for
the old-style BPF helper equivalents. bpf_rdonly_cast() is included in this
list as well as it returns PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED for an
unchecked object and is using fault-safe BPF_PROBE_MEM.

Note that only the void form of bpf_rdonly_cast() produced a register that
was readable without CAP_PERFMON. For a struct type id the kfunc returns
PTR_TO_BTF_ID | PTR_UNTRUSTED, whose dereference has always been gated in
check_ptr_to_btf_access(). The flag is not conditional on the type id, so
for the latter it only moves the rejection from the dereference to the call
itself, which is the better place to report it anyway.

The bpf_stream_vprintk() and bpf_stream_print_stack() kfuncs are marked
as well. The former ends up in the same bpf_bprintf_prepare() as the
bpf_snprintf() helper, where %pks, %pus and %pI4 read through a program-
supplied address and %pB resolves one into a symbol. The latter walks the
stack and prints each instruction pointer via %pS.

Fixes: 4665415975b0 ("bpf: Add bits iterator")
Fixes: 65ab5ac4df01 ("bpf: Add bpf_copy_from_user_str kfunc")
Fixes: f0f8a5b58f78 ("bpf: Add bpf_copy_from_user_task_str() kfunc")
Fixes: a498ee7576de ("bpf: Implement dynptr copy kfuncs")
Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
Fixes: e91370550f1f ("bpf: Add kfuncs for read-only string operations")
Fixes: 5ab154f1463a ("bpf: Introduce BPF standard streams")
Fixes: 19559e844184 ("bpf: add bpf_strcasecmp kfunc")
Fixes: b5b693f73589 ("bpf: add bpf_strcasestr,bpf_strncasestr kfuncs")
Fixes: 1dc669646762 ("bpf: add bpf_strncasecmp kfunc")
Fixes: 63328bb23f26 ("bpf: Add bpf_stream_print_stack stack dumping kfunc")
Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 kernel/bpf/helpers.c | 58 ++++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b3cc5c8fc875..8a0eeb4f6236 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -4883,7 +4883,7 @@ BTF_ID(func, bpf_cgroup_release_dtor)
 
 BTF_KFUNCS_START(common_btf_ids)
 BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx, KF_FASTCALL)
-BTF_ID_FLAGS(func, bpf_rdonly_cast, KF_FASTCALL)
+BTF_ID_FLAGS(func, bpf_rdonly_cast, KF_FASTCALL | KF_PERFMON)
 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)
@@ -4920,11 +4920,11 @@ BTF_ID_FLAGS(func, bpf_wq_set_callback, KF_IMPLICIT_ARGS)
 BTF_ID_FLAGS(func, bpf_wq_start)
 BTF_ID_FLAGS(func, bpf_preempt_disable)
 BTF_ID_FLAGS(func, bpf_preempt_enable)
-BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW)
+BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW | KF_PERFMON)
 BTF_ID_FLAGS(func, bpf_iter_bits_next, KF_ITER_NEXT | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_iter_bits_destroy, KF_ITER_DESTROY)
-BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE)
-BTF_ID_FLAGS(func, bpf_copy_from_user_task_str, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE | KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_copy_from_user_task_str, KF_SLEEPABLE | KF_PERFMON)
 BTF_ID_FLAGS(func, bpf_get_kmem_cache)
 BTF_ID_FLAGS(func, bpf_iter_kmem_cache_new, KF_ITER_NEW | KF_SLEEPABLE)
 BTF_ID_FLAGS(func, bpf_iter_kmem_cache_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPABLE)
@@ -4932,14 +4932,14 @@ BTF_ID_FLAGS(func, bpf_iter_kmem_cache_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
 BTF_ID_FLAGS(func, bpf_local_irq_save)
 BTF_ID_FLAGS(func, bpf_local_irq_restore)
 #ifdef CONFIG_BPF_EVENTS
-BTF_ID_FLAGS(func, bpf_probe_read_user_dynptr)
-BTF_ID_FLAGS(func, bpf_probe_read_kernel_dynptr)
-BTF_ID_FLAGS(func, bpf_probe_read_user_str_dynptr)
-BTF_ID_FLAGS(func, bpf_probe_read_kernel_str_dynptr)
-BTF_ID_FLAGS(func, bpf_copy_from_user_dynptr, KF_SLEEPABLE)
-BTF_ID_FLAGS(func, bpf_copy_from_user_str_dynptr, KF_SLEEPABLE)
-BTF_ID_FLAGS(func, bpf_copy_from_user_task_dynptr, KF_SLEEPABLE)
-BTF_ID_FLAGS(func, bpf_copy_from_user_task_str_dynptr, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_probe_read_user_dynptr, KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_probe_read_kernel_dynptr, KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_probe_read_user_str_dynptr, KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_probe_read_kernel_str_dynptr, KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_copy_from_user_dynptr, KF_SLEEPABLE | KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_copy_from_user_str_dynptr, KF_SLEEPABLE | KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_copy_from_user_task_dynptr, KF_SLEEPABLE | KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_copy_from_user_task_str_dynptr, KF_SLEEPABLE | KF_PERFMON)
 #endif
 #ifdef CONFIG_DMA_SHARED_BUFFER
 BTF_ID_FLAGS(func, bpf_iter_dmabuf_new, KF_ITER_NEW | KF_SLEEPABLE)
@@ -4947,26 +4947,26 @@ BTF_ID_FLAGS(func, bpf_iter_dmabuf_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPAB
 BTF_ID_FLAGS(func, bpf_iter_dmabuf_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
 #endif
 BTF_ID_FLAGS(func, __bpf_trap)
-BTF_ID_FLAGS(func, bpf_strcmp);
-BTF_ID_FLAGS(func, bpf_strcasecmp);
-BTF_ID_FLAGS(func, bpf_strncasecmp);
-BTF_ID_FLAGS(func, bpf_strchr);
-BTF_ID_FLAGS(func, bpf_strchrnul);
-BTF_ID_FLAGS(func, bpf_strnchr);
-BTF_ID_FLAGS(func, bpf_strrchr);
-BTF_ID_FLAGS(func, bpf_strlen);
-BTF_ID_FLAGS(func, bpf_strnlen);
-BTF_ID_FLAGS(func, bpf_strspn);
-BTF_ID_FLAGS(func, bpf_strcspn);
-BTF_ID_FLAGS(func, bpf_strstr);
-BTF_ID_FLAGS(func, bpf_strcasestr);
-BTF_ID_FLAGS(func, bpf_strnstr);
-BTF_ID_FLAGS(func, bpf_strncasestr);
+BTF_ID_FLAGS(func, bpf_strcmp, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strcasecmp, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strncasecmp, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strchr, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strchrnul, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strnchr, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strrchr, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strlen, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strnlen, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strspn, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strcspn, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strstr, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strcasestr, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strnstr, KF_PERFMON);
+BTF_ID_FLAGS(func, bpf_strncasestr, KF_PERFMON);
 #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 | KF_SPINLOCK_SAFE)
-BTF_ID_FLAGS(func, bpf_stream_print_stack, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE)
+BTF_ID_FLAGS(func, bpf_stream_vprintk, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE | KF_PERFMON)
+BTF_ID_FLAGS(func, bpf_stream_print_stack, KF_IMPLICIT_ARGS | KF_SPINLOCK_SAFE | KF_PERFMON)
 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)
-- 
2.43.0


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

* [PATCH bpf 3/4] bpf: Require CAP_PERFMON for untrusted read-only memory reads
  2026-09-10 14:21 [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Daniel Borkmann
  2026-09-10 14:21 ` [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory Daniel Borkmann
@ 2026-09-10 14:21 ` Daniel Borkmann
  2026-09-10 15:42   ` Alexei Starovoitov
  2026-09-10 14:21 ` [PATCH bpf 4/4] selftests/bpf: Add tests for the KF_PERFMON gates Daniel Borkmann
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Daniel Borkmann @ 2026-09-10 14:21 UTC (permalink / raw)
  To: ast; +Cc: memxor, eddyz87, info, bpf

Marking bpf_rdonly_cast() KF_PERFMON CAP-limits one producer of PTR_TO_MEM |
MEM_RDONLY | PTR_UNTRUSTED, but not the type itself. A global subprogram
argument tagged __arg_untrusted results in the same register with no kfunc
call.

Fixes: c4aa454c64ae ("bpf: support for void/primitive __arg_untrusted global func params")
Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 kernel/bpf/verifier.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5d61e74865a8..3f99b20e04fc 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6453,6 +6453,16 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
 			return -EACCES;
 		}
 
+		if (rdonly_untrusted && !env->allow_ptr_leaks) {
+			verbose(env, "%s access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
+				reg_type_str(env, reg->type));
+			bpf_diag_policy(
+				env, insn_idx, "read from untrusted read-only memory",
+				"the access requires CAP_PERFMON",
+				"Load the program with CAP_PERFMON, or avoid dereferencing untrusted pointers.");
+			return -EPERM;
+		}
+
 		/*
 		 * Accesses to untrusted PTR_TO_MEM are done through probe
 		 * instructions, hence no need to check bounds in that case.
-- 
2.43.0


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

* [PATCH bpf 4/4] selftests/bpf: Add tests for the KF_PERFMON gates
  2026-09-10 14:21 [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Daniel Borkmann
  2026-09-10 14:21 ` [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory Daniel Borkmann
  2026-09-10 14:21 ` [PATCH bpf 3/4] bpf: Require CAP_PERFMON for untrusted read-only memory reads Daniel Borkmann
@ 2026-09-10 14:21 ` Daniel Borkmann
  2026-09-10 15:03 ` [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Mykyta Yatsenko
  2026-09-10 15:10 ` bot+bpf-ci
  4 siblings, 0 replies; 12+ messages in thread
From: Daniel Borkmann @ 2026-09-10 14:21 UTC (permalink / raw)
  To: ast; +Cc: memxor, eddyz87, info, bpf

Add test cases where each one loads with CAP_BPF alone and checks that
the program is correctly rejected.

  # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_kfunc_perfmon
  [...]
  #627/1   verifier_kfunc_perfmon/rdonly_cast_noperfmon:OK
  #627/2   verifier_kfunc_perfmon/rdonly_cast_noperfmon @unpriv:OK
  #627/3   verifier_kfunc_perfmon/probe_read_kernel_dynptr_noperfmon:OK
  #627/4   verifier_kfunc_perfmon/probe_read_kernel_dynptr_noperfmon @unpriv:OK
  #627/5   verifier_kfunc_perfmon/stream_vprintk_noperfmon:OK
  #627/6   verifier_kfunc_perfmon/stream_vprintk_noperfmon @unpriv:OK
  #627/7   verifier_kfunc_perfmon/arg_untrusted_read_noperfmon:OK
  #627/8   verifier_kfunc_perfmon/arg_untrusted_read_noperfmon @unpriv:OK
  #627     verifier_kfunc_perfmon:OK
  Summary: 1/8 PASSED, 0 SKIPPED, 0/0 FAILED

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 .../selftests/bpf/prog_tests/verifier.c       |  2 +
 .../bpf/progs/verifier_kfunc_perfmon.c        | 63 +++++++++++++++++++
 2 files changed, 65 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_kfunc_perfmon.c

diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index 64ac49ad67e6..ec9e3907c75d 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -53,6 +53,7 @@
 #include "verifier_iterating_callbacks.skel.h"
 #include "verifier_jeq_infer_not_null.skel.h"
 #include "verifier_jit_convergence.skel.h"
+#include "verifier_kfunc_perfmon.skel.h"
 #include "verifier_ld_ind.skel.h"
 #include "verifier_ldsx.skel.h"
 #include "verifier_leak_ptr.skel.h"
@@ -216,6 +217,7 @@ void test_verifier_int_ptr(void)              { RUN(verifier_int_ptr); }
 void test_verifier_iterating_callbacks(void)  { RUN(verifier_iterating_callbacks); }
 void test_verifier_jeq_infer_not_null(void)   { RUN(verifier_jeq_infer_not_null); }
 void test_verifier_jit_convergence(void)      { RUN(verifier_jit_convergence); }
+void test_verifier_kfunc_perfmon(void)        { RUN(verifier_kfunc_perfmon); }
 void test_verifier_load_acquire(void)         { RUN(verifier_load_acquire); }
 void test_verifier_ld_ind(void)               { RUN(verifier_ld_ind); }
 void test_verifier_ldsx(void)                  { RUN(verifier_ldsx); }
diff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_perfmon.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_perfmon.c
new file mode 100644
index 000000000000..c6adbb4816ce
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_perfmon.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+void *user_ptr;
+char dynptr_buf[8];
+u64 kaddr;
+
+SEC("socket")
+__success
+__caps_unpriv(CAP_BPF)
+__failure_unpriv
+__msg_unpriv("bpf_rdonly_cast is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
+int rdonly_cast_noperfmon(void *ctx)
+{
+	char *p = bpf_rdonly_cast(0, 0);
+
+	return p[0x7fff];
+}
+
+SEC("socket")
+__success
+__caps_unpriv(CAP_BPF)
+__failure_unpriv
+__msg_unpriv("bpf_probe_read_kernel_dynptr is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
+int probe_read_kernel_dynptr_noperfmon(void *ctx)
+{
+	struct bpf_dynptr dptr;
+
+	bpf_dynptr_from_mem(dynptr_buf, sizeof(dynptr_buf), 0, &dptr);
+	bpf_probe_read_kernel_dynptr(&dptr, 0, sizeof(dynptr_buf), user_ptr);
+	return 0;
+}
+
+SEC("socket")
+__success
+__caps_unpriv(CAP_BPF)
+__failure_unpriv
+__msg_unpriv("bpf_stream_vprintk is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
+int stream_vprintk_noperfmon(void *ctx)
+{
+	bpf_stream_printk(BPF_STDOUT, "%pB", (void *)kaddr);
+	return 0;
+}
+
+__weak int subprog_untrusted_read(void *p __arg_untrusted)
+{
+	return *(char *)p;
+}
+
+SEC("socket")
+__success
+__caps_unpriv(CAP_BPF)
+__failure_unpriv
+__msg_unpriv("rdonly_untrusted_mem access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
+int arg_untrusted_read_noperfmon(void *ctx)
+{
+	return subprog_untrusted_read(0);
+}
+
+char _license[] SEC("license") = "GPL";
-- 
2.43.0


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

* Re: [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag
  2026-09-10 14:21 [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Daniel Borkmann
                   ` (2 preceding siblings ...)
  2026-09-10 14:21 ` [PATCH bpf 4/4] selftests/bpf: Add tests for the KF_PERFMON gates Daniel Borkmann
@ 2026-09-10 15:03 ` Mykyta Yatsenko
  2026-09-10 15:14   ` Kumar Kartikeya Dwivedi
  2026-09-10 15:10 ` bot+bpf-ci
  4 siblings, 1 reply; 12+ messages in thread
From: Mykyta Yatsenko @ 2026-09-10 15:03 UTC (permalink / raw)
  To: Daniel Borkmann, ast; +Cc: memxor, eddyz87, info, bpf

On 9/10/26 3:21 PM, Daniel Borkmann wrote:
> Tracing related BPF helpers e.g. under bpf_base_func_proto() are gated
> behind CAP_PERFMON. However, the same is currently not true for kfuncs
> and they are accessible via plain CAP_BPF. Add a new KF_PERFMON flag
> which can be used such that check_kfunc_call() ensures env->allow_ptr_leaks
> is permitted. This follows similar pattern to existing KF_DESTRUCTIVE flag.
> 

This problem has been reported and patch sent some time ago:
https://lore.kernel.org/all/20260615-f01-07-dynptr-probe-read-cap-v1-0-e626cd61a381@mails.tsinghua.edu.cn/

> The rejection returns -EPERM to match the other CAP_PERFMON gates in the
> verifier, that is, check_ptr_to_btf_access() and check_ptr_to_map_access(),
> which report the very same policy to user space.
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> ---
>  Documentation/bpf/kfuncs.rst | 10 ++++++++++
>  include/linux/btf.h          |  1 +
>  kernel/bpf/verifier.c        | 15 +++++++++++++++
>  3 files changed, 26 insertions(+)
> 
> diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst
> index 85f73e0bbd0f..6691fe8a32c3 100644
> --- a/Documentation/bpf/kfuncs.rst
> +++ b/Documentation/bpf/kfuncs.rst
> @@ -486,6 +486,16 @@ Example usage in BPF program:
>  	/* note that the last argument is omitted */
>          bpf_task_work_schedule_signal(task, &work->tw, &arrmap, task_work_callback);
>  
> +2.5.10 KF_PERFMON flag
> +----------------------
> +
> +The KF_PERFMON flag is used for kfuncs that can expose kernel memory or kernel
> +addresses to the BPF program, for example by reading through a pointer that the
> +verifier does not check. Calling such a kfunc requires CAP_PERFMON, or
> +CAP_SYS_ADMIN, in the same way that the equivalent BPF helpers are gated in
> +bpf_base_func_proto(). A program loaded with CAP_BPF alone is rejected at load
> +time.
> +
>  2.6 Registering the kfuncs
>  --------------------------
>  
> diff --git a/include/linux/btf.h b/include/linux/btf.h
> index 89d5a5c4f117..7c62ea17b116 100644
> --- a/include/linux/btf.h
> +++ b/include/linux/btf.h
> @@ -80,6 +80,7 @@
>  #define KF_ARENA_ARG2   (1 << 15) /* kfunc takes an arena pointer as its second argument */
>  #define KF_IMPLICIT_ARGS (1 << 16) /* kfunc has implicit arguments supplied by the verifier */
>  #define KF_SPINLOCK_SAFE (1 << 17) /* kfunc is allowed inside bpf_spin_lock-ed region */
> +#define KF_PERFMON      (1 << 18) /* kfunc requires CAP_PERFMON */
>  
>  /*
>   * 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 45234e2fbee6..5d61e74865a8 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11356,6 +11356,11 @@ static bool is_kfunc_destructive(struct bpf_call_arg_meta *meta)
>  	return meta->kfunc_flags & KF_DESTRUCTIVE;
>  }
>  
> +static bool is_kfunc_perfmon(struct bpf_call_arg_meta *meta)
> +{
> +	return meta->kfunc_flags & KF_PERFMON;
> +}
> +
>  static bool is_kfunc_rcu(struct bpf_call_arg_meta *meta)
>  {
>  	return meta->kfunc_flags & KF_RCU;
> @@ -13834,6 +13839,16 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
>  		return -EACCES;
>  	}
>  
> +	if (is_kfunc_perfmon(&meta) && !env->allow_ptr_leaks) {
> +		verbose(env, "%s is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
> +			func_name);
> +		operation = bpf_diag_fmt(env, "kfunc %s", func_name);
> +		bpf_diag_policy(
> +			env, insn_idx, operation, "the kfunc requires CAP_PERFMON",
> +			"Load the program with CAP_PERFMON, or avoid the kfunc.");
> +		return -EPERM;
> +	}
> +
>  	sleepable = bpf_is_kfunc_sleepable(&meta);
>  	if (sleepable && !in_sleepable(env)) {
>  		verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name);


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

* Re: [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag
  2026-09-10 14:21 [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Daniel Borkmann
                   ` (3 preceding siblings ...)
  2026-09-10 15:03 ` [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Mykyta Yatsenko
@ 2026-09-10 15:10 ` bot+bpf-ci
  4 siblings, 0 replies; 12+ messages in thread
From: bot+bpf-ci @ 2026-09-10 15:10 UTC (permalink / raw)
  To: daniel, ast
  Cc: memxor, eddyz87, info, bpf, ast, andrii, daniel, martin.lau,
	eddyz87, yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1335 bytes --]

> bpf: Add KF_PERFMON kfunc flag
>
> Tracing related BPF helpers e.g. under bpf_base_func_proto() are gated
> behind CAP_PERFMON. However, the same is currently not true for kfuncs
> and they are accessible via plain CAP_BPF. Add a new KF_PERFMON flag
> which can be used such that check_kfunc_call() ensures env->allow_ptr_leaks
> is permitted. This follows similar pattern to existing KF_DESTRUCTIVE flag.
>
> The rejection returns -EPERM to match the other CAP_PERFMON gates in the
> verifier, that is, check_ptr_to_btf_access() and check_ptr_to_map_access(),
> which report the very same policy to user space.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

This looks like a security fix. Should this include:

  Fixes: e6ac2450d6de ("bpf: Support bpf program calling kernel function")

The bug was introduced when kfunc support was first added in that commit,
which created check_kfunc_call() without any capability checks for kfuncs
that can expose kernel memory or addresses, even though equivalent BPF
helpers in bpf_base_func_proto() were already gated behind CAP_PERFMON.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34490344966

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

* Re: [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory
  2026-09-10 14:21 ` [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory Daniel Borkmann
@ 2026-09-10 15:10   ` bot+bpf-ci
  2026-09-10 15:41   ` Alexei Starovoitov
  1 sibling, 0 replies; 12+ messages in thread
From: bot+bpf-ci @ 2026-09-10 15:10 UTC (permalink / raw)
  To: daniel, ast
  Cc: memxor, eddyz87, info, bpf, ast, andrii, daniel, martin.lau,
	eddyz87, yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 5874 bytes --]

> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> index b3cc5c8fc875..8a0eeb4f6236 100644
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c

Alexei Starovoitov (BPF maintainer) explicitly rejected a similar approach
in June 2026. Nuoqi Gui submitted a patch series to gate dynptr probe-read
kfuncs (bpf_probe_read_user_dynptr, bpf_probe_read_kernel_dynptr,
bpf_probe_read_user_str_dynptr, bpf_probe_read_kernel_str_dynptr) with
CAP_PERFMON.

Alexei responded with:

> On Mon Jun 15, 2026 at 1:31 AM PDT, Nuoqi Gui wrote:
> > The dynptr probe-read kfuncs are registered as common kfuncs. That lets a
> > program with the generic kfunc privilege gate call
> > bpf_probe_read_kernel_dynptr(), while the legacy bpf_probe_read_kernel()
> > helper is exposed only with CAP_PERFMON and is blocked by kernel-read
> > lockdown.
>
> It's fine as-is. Won't fix.
>
> pw-bot: cr

Reference: https://lore.kernel.org/bpf/DJ9QOWVIXFHR.1S8UL5H0USVCB@gmail.com/

The current patch takes the same approach of requiring CAP_PERFMON for
these kfuncs, which directly contradicts the maintainer's prior decision.

Does this need to be addressed or justified before proceeding?

> @@ -4920,11 +4920,11 @@ BTF_ID_FLAGS(func, bpf_wq_set_callback, KF_IMPLICIT_ARGS)
>  BTF_ID_FLAGS(func, bpf_wq_start)
>  BTF_ID_FLAGS(func, bpf_preempt_disable)
>  BTF_ID_FLAGS(func, bpf_preempt_enable)
> -BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW)
> +BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW | KF_PERFMON)
>  BTF_ID_FLAGS(func, bpf_iter_bits_next, KF_ITER_NEXT | KF_RET_NULL)
>  BTF_ID_FLAGS(func, bpf_iter_bits_destroy, KF_ITER_DESTROY)
> -BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE)
> -BTF_ID_FLAGS(func, bpf_copy_from_user_task_str, KF_SLEEPABLE)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE | KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_task_str, KF_SLEEPABLE | KF_PERFMON)
>  BTF_ID_FLAGS(func, bpf_get_kmem_cache)

After this series every kfunc in common_btf_ids that takes a
program-supplied address is KF_PERFMON except bpf_get_kmem_cache(),
which is left with no flags two lines below the newly gated
bpf_copy_from_user_task_str entry.

Looking at mm/slab_common.c bpf_get_kmem_cache():

    __bpf_kfunc struct kmem_cache *bpf_get_kmem_cache(u64 addr)
    {
            struct slab *slab;

            if (!virt_addr_valid((void *)(long)addr))
                    return NULL;
            slab = virt_to_slab((void *)(long)addr);
            return slab ? slab->slab_cache : NULL;
    }

The kfunc takes a raw scalar address that the verifier does not
constrain and dereferences the page/slab metadata for it. Field reads
on the returned pointer are still blocked (PTR_TO_BTF_ID | PTR_UNTRUSTED
-> check_ptr_to_btf_access() -EPERM), but the NULL/non-NULL result is
observable.

So a CAP_BPF-only program can still probe whether an arbitrary kernel
address is a valid slab object. Once bpf_rdonly_cast() and the
probe-read kfuncs are gated, this appears to be the remaining ungated
address oracle in the same list.

Is this kfunc considered out of scope for this patch, or should it also
be gated?

> @@ -4932,14 +4932,14 @@ BTF_ID_FLAGS(func, bpf_iter_kmem_cache_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
>  BTF_ID_FLAGS(func, bpf_local_irq_save)
>  BTF_ID_FLAGS(func, bpf_local_irq_restore)
>  #ifdef CONFIG_BPF_EVENTS
> -BTF_ID_FLAGS(func, bpf_probe_read_user_dynptr)
> -BTF_ID_FLAGS(func, bpf_probe_read_kernel_dynptr)
> -BTF_ID_FLAGS(func, bpf_probe_read_user_str_dynptr)
> -BTF_ID_FLAGS(func, bpf_probe_read_kernel_str_dynptr)
> -BTF_ID_FLAGS(func, bpf_copy_from_user_dynptr, KF_SLEEPABLE)
> -BTF_ID_FLAGS(func, bpf_copy_from_user_str_dynptr, KF_SLEEPABLE)
> -BTF_ID_FLAGS(func, bpf_copy_from_user_task_dynptr, KF_SLEEPABLE)
> -BTF_ID_FLAGS(func, bpf_copy_from_user_task_str_dynptr, KF_SLEEPABLE)
> +BTF_ID_FLAGS(func, bpf_probe_read_user_dynptr, KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_probe_read_kernel_dynptr, KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_probe_read_user_str_dynptr, KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_probe_read_kernel_str_dynptr, KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_dynptr, KF_SLEEPABLE | KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_str_dynptr, KF_SLEEPABLE | KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_task_dynptr, KF_SLEEPABLE | KF_PERFMON)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_task_str_dynptr, KF_SLEEPABLE | KF_PERFMON)
>  #endif

The commit message states these kfuncs are now gated "similarly as we do
for the old-style BPF helper equivalents." The helper equivalents are
gated by two things, not one. Looking at kernel/bpf/helpers.c
bpf_base_func_proto():

    case BPF_FUNC_probe_read_kernel:
            return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
                   NULL : &bpf_probe_read_kernel_proto;
    ...
    case BPF_FUNC_probe_read_kernel_str:
            return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
                   NULL : &bpf_probe_read_kernel_str_proto;

KF_PERFMON restores the capability half of that gate, but
LOCKDOWN_BPF_READ_KERNEL has no kfunc counterpart anywhere in the tree
(the only users are bpf_base_func_proto() and tracing_func_proto()).

So with lockdown=confidentiality, bpf_probe_read_kernel_dynptr(),
bpf_probe_read_kernel_str_dynptr(), bpf_iter_bits_new(), the bpf_str*()
kfuncs and bpf_stream_vprintk("%pks"/"%pB") still read kernel RAM for a
CAP_PERFMON holder while the equivalent helpers are refused.

Should the commit message acknowledge that this only addresses the
capability half of the gate, or should a follow-up gate also check
lockdown?

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34490344966

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

* Re: [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag
  2026-09-10 15:03 ` [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Mykyta Yatsenko
@ 2026-09-10 15:14   ` Kumar Kartikeya Dwivedi
  2026-09-10 15:21     ` Mykyta Yatsenko
  0 siblings, 1 reply; 12+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-09-10 15:14 UTC (permalink / raw)
  To: Mykyta Yatsenko, Daniel Borkmann, ast; +Cc: eddyz87, info, bpf

On Thu Sep 10, 2026 at 5:03 PM CEST, Mykyta Yatsenko wrote:
> On 9/10/26 3:21 PM, Daniel Borkmann wrote:
>> Tracing related BPF helpers e.g. under bpf_base_func_proto() are gated
>> behind CAP_PERFMON. However, the same is currently not true for kfuncs
>> and they are accessible via plain CAP_BPF. Add a new KF_PERFMON flag
>> which can be used such that check_kfunc_call() ensures env->allow_ptr_leaks
>> is permitted. This follows similar pattern to existing KF_DESTRUCTIVE flag.
>>
>
> This problem has been reported and patch sent some time ago:
> https://lore.kernel.org/all/20260615-f01-07-dynptr-probe-read-cap-v1-0-e626cd61a381@mails.tsinghua.edu.cn/
>

We ended up discussing this and decided to go ahead, since it's a bit weird to
continue to have the discrepancy against helpers that have similar restrictions.
In practice it won't matter much to actual users, but easier to just fix it and
put the thing to rest.  This one is also a more comprehensive fix compared to
Nuoqi's.

> [...]

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

* Re: [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag
  2026-09-10 15:14   ` Kumar Kartikeya Dwivedi
@ 2026-09-10 15:21     ` Mykyta Yatsenko
  0 siblings, 0 replies; 12+ messages in thread
From: Mykyta Yatsenko @ 2026-09-10 15:21 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, Daniel Borkmann, ast; +Cc: eddyz87, info, bpf



On 9/10/26 4:14 PM, Kumar Kartikeya Dwivedi wrote:
> On Thu Sep 10, 2026 at 5:03 PM CEST, Mykyta Yatsenko wrote:
>> On 9/10/26 3:21 PM, Daniel Borkmann wrote:
>>> Tracing related BPF helpers e.g. under bpf_base_func_proto() are gated
>>> behind CAP_PERFMON. However, the same is currently not true for kfuncs
>>> and they are accessible via plain CAP_BPF. Add a new KF_PERFMON flag
>>> which can be used such that check_kfunc_call() ensures env->allow_ptr_leaks
>>> is permitted. This follows similar pattern to existing KF_DESTRUCTIVE flag.
>>>
>>
>> This problem has been reported and patch sent some time ago:
>> https://lore.kernel.org/all/20260615-f01-07-dynptr-probe-read-cap-v1-0-e626cd61a381@mails.tsinghua.edu.cn/
>>
> 
> We ended up discussing this and decided to go ahead, since it's a bit weird to
> continue to have the discrepancy against helpers that have similar restrictions.
> In practice it won't matter much to actual users, but easier to just fix it and
> put the thing to rest.  This one is also a more comprehensive fix compared to
> Nuoqi's.
> 
Thanks for the context, appreciate it!>> [...]


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

* Re: [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory
  2026-09-10 14:21 ` [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory Daniel Borkmann
  2026-09-10 15:10   ` bot+bpf-ci
@ 2026-09-10 15:41   ` Alexei Starovoitov
  2026-09-10 15:53     ` Daniel Borkmann
  1 sibling, 1 reply; 12+ messages in thread
From: Alexei Starovoitov @ 2026-09-10 15:41 UTC (permalink / raw)
  To: Daniel Borkmann, ast; +Cc: memxor, eddyz87, info, bpf

On Thu Sep 10, 2026 at 7:21 AM PDT, Daniel Borkmann wrote:
> Mark fault-safe probe reading kfuncs as KF_PERFMON, similarly as we do for
> the old-style BPF helper equivalents. bpf_rdonly_cast() is included in this
> list as well as it returns PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED for an
> unchecked object and is using fault-safe BPF_PROBE_MEM.
>
> Note that only the void form of bpf_rdonly_cast() produced a register that
> was readable without CAP_PERFMON. For a struct type id the kfunc returns
> PTR_TO_BTF_ID | PTR_UNTRUSTED, whose dereference has always been gated in
> check_ptr_to_btf_access(). The flag is not conditional on the type id, so
> for the latter it only moves the rejection from the dereference to the call
> itself, which is the better place to report it anyway.
>
> The bpf_stream_vprintk() and bpf_stream_print_stack() kfuncs are marked
> as well. The former ends up in the same bpf_bprintf_prepare() as the
> bpf_snprintf() helper, where %pks, %pus and %pI4 read through a program-
> supplied address and %pB resolves one into a symbol. The latter walks the
> stack and prints each instruction pointer via %pS.
>
> Fixes: 4665415975b0 ("bpf: Add bits iterator")
> Fixes: 65ab5ac4df01 ("bpf: Add bpf_copy_from_user_str kfunc")
> Fixes: f0f8a5b58f78 ("bpf: Add bpf_copy_from_user_task_str() kfunc")
> Fixes: a498ee7576de ("bpf: Implement dynptr copy kfuncs")
> Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
> Fixes: e91370550f1f ("bpf: Add kfuncs for read-only string operations")
> Fixes: 5ab154f1463a ("bpf: Introduce BPF standard streams")
> Fixes: 19559e844184 ("bpf: add bpf_strcasecmp kfunc")
> Fixes: b5b693f73589 ("bpf: add bpf_strcasestr,bpf_strncasestr kfuncs")
> Fixes: 1dc669646762 ("bpf: add bpf_strncasecmp kfunc")
> Fixes: 63328bb23f26 ("bpf: Add bpf_stream_print_stack stack dumping kfunc")

Let's drop this Fixes list altogether, since it will only cause
headaches to stable folks. We don't need to backport this everywhere.
Not really an issue.
CAP_BPF alone can leak memory via HW speculation,
so this patch isn't strictly necessary, but I don't mind closing the hole
since AI keeps reporting it.

Also pls add bpf_get_kmem_cache() as AI suggested.


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

* Re: [PATCH bpf 3/4] bpf: Require CAP_PERFMON for untrusted read-only memory reads
  2026-09-10 14:21 ` [PATCH bpf 3/4] bpf: Require CAP_PERFMON for untrusted read-only memory reads Daniel Borkmann
@ 2026-09-10 15:42   ` Alexei Starovoitov
  0 siblings, 0 replies; 12+ messages in thread
From: Alexei Starovoitov @ 2026-09-10 15:42 UTC (permalink / raw)
  To: Daniel Borkmann, ast; +Cc: memxor, eddyz87, info, bpf

On Thu Sep 10, 2026 at 7:21 AM PDT, Daniel Borkmann wrote:
> Marking bpf_rdonly_cast() KF_PERFMON CAP-limits one producer of PTR_TO_MEM |
> MEM_RDONLY | PTR_UNTRUSTED, but not the type itself. A global subprogram
> argument tagged __arg_untrusted results in the same register with no kfunc
> call.
>
> Fixes: c4aa454c64ae ("bpf: support for void/primitive __arg_untrusted global func params")
> Reported-by: STAR Labs SG <info@starlabs.sg>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> ---
>  kernel/bpf/verifier.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5d61e74865a8..3f99b20e04fc 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -6453,6 +6453,16 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
>  			return -EACCES;
>  		}
>  
> +		if (rdonly_untrusted && !env->allow_ptr_leaks) {
> +			verbose(env, "%s access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
> +				reg_type_str(env, reg->type));
> +			bpf_diag_policy(
> +				env, insn_idx, "read from untrusted read-only memory",
> +				"the access requires CAP_PERFMON",
> +				"Load the program with CAP_PERFMON, or avoid dereferencing untrusted pointers.");

That's an odd formatting.
	bpf_diag_policy(env, insn_idx, "read from untrusted read-only memory",
			"the access requires CAP_PERFMON",

would look more normal.

pw-bot: cr

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

* Re: [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory
  2026-09-10 15:41   ` Alexei Starovoitov
@ 2026-09-10 15:53     ` Daniel Borkmann
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Borkmann @ 2026-09-10 15:53 UTC (permalink / raw)
  To: Alexei Starovoitov, ast; +Cc: memxor, eddyz87, info, bpf

On 9/10/26 5:41 PM, Alexei Starovoitov wrote:
> On Thu Sep 10, 2026 at 7:21 AM PDT, Daniel Borkmann wrote:
>> Mark fault-safe probe reading kfuncs as KF_PERFMON, similarly as we do for
>> the old-style BPF helper equivalents. bpf_rdonly_cast() is included in this
>> list as well as it returns PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED for an
>> unchecked object and is using fault-safe BPF_PROBE_MEM.
>>
>> Note that only the void form of bpf_rdonly_cast() produced a register that
>> was readable without CAP_PERFMON. For a struct type id the kfunc returns
>> PTR_TO_BTF_ID | PTR_UNTRUSTED, whose dereference has always been gated in
>> check_ptr_to_btf_access(). The flag is not conditional on the type id, so
>> for the latter it only moves the rejection from the dereference to the call
>> itself, which is the better place to report it anyway.
>>
>> The bpf_stream_vprintk() and bpf_stream_print_stack() kfuncs are marked
>> as well. The former ends up in the same bpf_bprintf_prepare() as the
>> bpf_snprintf() helper, where %pks, %pus and %pI4 read through a program-
>> supplied address and %pB resolves one into a symbol. The latter walks the
>> stack and prints each instruction pointer via %pS.
>>
>> Fixes: 4665415975b0 ("bpf: Add bits iterator")
>> Fixes: 65ab5ac4df01 ("bpf: Add bpf_copy_from_user_str kfunc")
>> Fixes: f0f8a5b58f78 ("bpf: Add bpf_copy_from_user_task_str() kfunc")
>> Fixes: a498ee7576de ("bpf: Implement dynptr copy kfuncs")
>> Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
>> Fixes: e91370550f1f ("bpf: Add kfuncs for read-only string operations")
>> Fixes: 5ab154f1463a ("bpf: Introduce BPF standard streams")
>> Fixes: 19559e844184 ("bpf: add bpf_strcasecmp kfunc")
>> Fixes: b5b693f73589 ("bpf: add bpf_strcasestr,bpf_strncasestr kfuncs")
>> Fixes: 1dc669646762 ("bpf: add bpf_strncasecmp kfunc")
>> Fixes: 63328bb23f26 ("bpf: Add bpf_stream_print_stack stack dumping kfunc")
> 
> Let's drop this Fixes list altogether, since it will only cause
> headaches to stable folks. We don't need to backport this everywhere.
> Not really an issue.
> CAP_BPF alone can leak memory via HW speculation,
> so this patch isn't strictly necessary, but I don't mind closing the hole
> since AI keeps reporting it.
> 
> Also pls add bpf_get_kmem_cache() as AI suggested.

Ack, will address and also the one from your other email.

Thanks,
Daniel

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

end of thread, other threads:[~2026-09-10 15:53 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-10 14:21 [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Daniel Borkmann
2026-09-10 14:21 ` [PATCH bpf 2/4] bpf: Require CAP_PERFMON for kfuncs reading memory Daniel Borkmann
2026-09-10 15:10   ` bot+bpf-ci
2026-09-10 15:41   ` Alexei Starovoitov
2026-09-10 15:53     ` Daniel Borkmann
2026-09-10 14:21 ` [PATCH bpf 3/4] bpf: Require CAP_PERFMON for untrusted read-only memory reads Daniel Borkmann
2026-09-10 15:42   ` Alexei Starovoitov
2026-09-10 14:21 ` [PATCH bpf 4/4] selftests/bpf: Add tests for the KF_PERFMON gates Daniel Borkmann
2026-09-10 15:03 ` [PATCH bpf 1/4] bpf: Add KF_PERFMON kfunc flag Mykyta Yatsenko
2026-09-10 15:14   ` Kumar Kartikeya Dwivedi
2026-09-10 15:21     ` Mykyta Yatsenko
2026-09-10 15:10 ` bot+bpf-ci

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.