* [PATCH bpf-next v3 0/2] libbpf: clarify raw-address single kprobe attach behavior
@ 2026-03-31 9:37 Hoyeon Lee
2026-03-31 9:37 ` [PATCH bpf-next v3 1/2] " Hoyeon Lee
2026-03-31 9:37 ` [PATCH bpf-next v3 2/2] selftests/bpf: add test for raw-address single kprobe attach Hoyeon Lee
0 siblings, 2 replies; 3+ messages in thread
From: Hoyeon Lee @ 2026-03-31 9:37 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, Shuah Khan, Feng Yang, linux-kselftest,
linux-kernel
Today libbpf documents single-kprobe attach through func_name, with an
optional offset. For the PMU-based non-legacy path, func_name = NULL
with an absolute address in offset already works as well, but that is
not described in the API.
This patchset clarifies this behavior. The first commit clarifies that,
for the PMU-based path, callers can use func_name = NULL with an
absolute address in offset for raw-address attach, and makes legacy
tracefs/debugfs kprobes reject that form. The second commit adds PERF
and LINK selftests for the raw-address form, and checks that LEGACY
rejects it.
---
Changes in v3:
- Drop bpf_kprobe_opts.addr and reuse offset when func_name is NULL
- Make legacy tracefs/debugfs kprobes reject the raw-address form
- Update selftests to cover PERF/LINK raw-address attach and LEGACY reject
Changes in v2:
- Fix line wrapping and indentation
Hoyeon Lee (2):
libbpf: clarify raw-address single kprobe attach behavior
selftests/bpf: add test for raw-address single kprobe attach
tools/lib/bpf/libbpf.c | 33 ++++++--
tools/lib/bpf/libbpf.h | 3 +-
.../selftests/bpf/prog_tests/attach_probe.c | 82 +++++++++++++++++++
3 files changed, 108 insertions(+), 10 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH bpf-next v3 1/2] libbpf: clarify raw-address single kprobe attach behavior
2026-03-31 9:37 [PATCH bpf-next v3 0/2] libbpf: clarify raw-address single kprobe attach behavior Hoyeon Lee
@ 2026-03-31 9:37 ` Hoyeon Lee
2026-03-31 9:37 ` [PATCH bpf-next v3 2/2] selftests/bpf: add test for raw-address single kprobe attach Hoyeon Lee
1 sibling, 0 replies; 3+ messages in thread
From: Hoyeon Lee @ 2026-03-31 9:37 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, Shuah Khan, Feng Yang, linux-kselftest,
linux-kernel
bpf_program__attach_kprobe_opts() documents single-kprobe attach
through func_name, with an optional offset. For the PMU-based
non-legacy path, func_name = NULL with an absolute address in offset
already works as well, but that is not described in the API.
This commit clarifies this existing non-legacy behavior. For PMU-based
attach, callers can use func_name = NULL with an absolute address in
offset as the raw-address form. For legacy tracefs/debugfs kprobes,
reject this form explicitly.
Signed-off-by: Hoyeon Lee <hoyeon.lee@suse.com>
---
tools/lib/bpf/libbpf.c | 33 ++++++++++++++++++++++++---------
tools/lib/bpf/libbpf.h | 3 ++-
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 9ea41f40dc82..8cf90a073455 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -28,6 +28,7 @@
#include <asm/unistd.h>
#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/kallsyms.h>
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/filter.h>
@@ -11523,7 +11524,8 @@ static int determine_uprobe_retprobe_bit(void)
#define PERF_UPROBE_REF_CTR_OFFSET_SHIFT 32
static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
- uint64_t offset, int pid, size_t ref_ctr_off)
+ uint64_t offset_or_addr, int pid,
+ size_t ref_ctr_off)
{
const size_t attr_sz = sizeof(struct perf_event_attr);
struct perf_event_attr attr;
@@ -11558,7 +11560,7 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
attr.type = type;
attr.config |= (__u64)ref_ctr_off << PERF_UPROBE_REF_CTR_OFFSET_SHIFT;
attr.config1 = ptr_to_u64(name); /* kprobe_func or uprobe_path */
- attr.config2 = offset; /* kprobe_addr or probe_offset */
+ attr.config2 = offset_or_addr; /* kprobe_addr or probe_offset */
/* pid filter is meaningful only for uprobes */
pfd = syscall(__NR_perf_event_open, &attr,
@@ -11648,6 +11650,15 @@ static void gen_probe_legacy_event_name(char *buf, size_t buf_sz,
}
}
+static void gen_kprobe_target(char *buf, size_t buf_sz, const char *name,
+ uint64_t offset_or_addr)
+{
+ if (name)
+ snprintf(buf, buf_sz, "%s+0x%" PRIx64, name, offset_or_addr);
+ else
+ snprintf(buf, buf_sz, "0x%" PRIx64, offset_or_addr);
+}
+
static int add_kprobe_event_legacy(const char *probe_name, bool retprobe,
const char *kfunc_name, size_t offset)
{
@@ -11781,6 +11792,7 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
const struct bpf_kprobe_opts *opts)
{
DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
+ char probe_target[KSYM_NAME_LEN + 32];
enum probe_attach_mode attach_mode;
char *legacy_probe = NULL;
struct bpf_link *link;
@@ -11816,6 +11828,11 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
default:
return libbpf_err_ptr(-EINVAL);
}
+ if (!func_name && legacy)
+ return libbpf_err_ptr(-ENOTSUP);
+
+ gen_kprobe_target(probe_target, sizeof(probe_target),
+ func_name, offset);
if (!legacy) {
pfd = perf_event_open_probe(false /* uprobe */, retprobe,
@@ -11835,21 +11852,19 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
offset, -1 /* pid */);
}
if (pfd < 0) {
- err = -errno;
- pr_warn("prog '%s': failed to create %s '%s+0x%zx' perf event: %s\n",
+ err = pfd;
+ pr_warn("prog '%s': failed to create %s '%s' perf event: %s\n",
prog->name, retprobe ? "kretprobe" : "kprobe",
- func_name, offset,
- errstr(err));
+ probe_target, errstr(err));
goto err_out;
}
link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
err = libbpf_get_error(link);
if (err) {
close(pfd);
- pr_warn("prog '%s': failed to attach to %s '%s+0x%zx': %s\n",
+ pr_warn("prog '%s': failed to attach to %s '%s': %s\n",
prog->name, retprobe ? "kretprobe" : "kprobe",
- func_name, offset,
- errstr(err));
+ probe_target, errstr(err));
goto err_clean_legacy;
}
if (legacy) {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 0be34852350f..f75f3ab0f20c 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -557,7 +557,7 @@ struct bpf_kprobe_opts {
size_t sz;
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
__u64 bpf_cookie;
- /* function's offset to install kprobe to */
+ /* function offset, or raw address if func_name == NULL (non-legacy) */
size_t offset;
/* kprobe is return probe */
bool retprobe;
@@ -565,6 +565,7 @@ struct bpf_kprobe_opts {
enum probe_attach_mode attach_mode;
size_t :0;
};
+
#define bpf_kprobe_opts__last_field attach_mode
LIBBPF_API struct bpf_link *
--
2.52.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH bpf-next v3 2/2] selftests/bpf: add test for raw-address single kprobe attach
2026-03-31 9:37 [PATCH bpf-next v3 0/2] libbpf: clarify raw-address single kprobe attach behavior Hoyeon Lee
2026-03-31 9:37 ` [PATCH bpf-next v3 1/2] " Hoyeon Lee
@ 2026-03-31 9:37 ` Hoyeon Lee
1 sibling, 0 replies; 3+ messages in thread
From: Hoyeon Lee @ 2026-03-31 9:37 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, Shuah Khan, Feng Yang, linux-kselftest,
linux-kernel
Currently, attach_probe covers manual single-kprobe attaches by
func_name, but not the raw-address form that the PMU-based
single-kprobe path can accept.
This commit adds PERF and LINK raw-address subtests by resolving
SYS_NANOSLEEP_KPROBE_NAME through kallsyms, passing the absolute address
in bpf_kprobe_opts.offset with func_name = NULL, and verifying that
kprobe and kretprobe are still triggered. It also verifies that LEGACY
rejects the same form.
Signed-off-by: Hoyeon Lee <hoyeon.lee@suse.com>
---
.../selftests/bpf/prog_tests/attach_probe.c | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
index 9e77e5da7097..817c4794d54e 100644
--- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c
+++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
@@ -123,6 +123,82 @@ static void test_attach_probe_manual(enum probe_attach_mode attach_mode)
test_attach_probe_manual__destroy(skel);
}
+/* manual attach address-based kprobe/kretprobe testings */
+static void test_attach_kprobe_by_addr(enum probe_attach_mode attach_mode)
+{
+ DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, kprobe_opts);
+ struct test_attach_probe_manual *skel;
+ unsigned long func_addr;
+
+ if (!ASSERT_OK(load_kallsyms(), "load_kallsyms"))
+ return;
+
+ func_addr = ksym_get_addr(SYS_NANOSLEEP_KPROBE_NAME);
+ if (!ASSERT_NEQ(func_addr, 0UL, "func_addr"))
+ return;
+
+ skel = test_attach_probe_manual__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_kprobe_manual_open_and_load"))
+ return;
+
+ kprobe_opts.attach_mode = attach_mode;
+ kprobe_opts.retprobe = false;
+ kprobe_opts.offset = func_addr;
+ skel->links.handle_kprobe =
+ bpf_program__attach_kprobe_opts(skel->progs.handle_kprobe,
+ NULL, &kprobe_opts);
+ if (!ASSERT_OK_PTR(skel->links.handle_kprobe, "attach_kprobe_by_addr"))
+ goto cleanup;
+
+ kprobe_opts.retprobe = true;
+ skel->links.handle_kretprobe =
+ bpf_program__attach_kprobe_opts(skel->progs.handle_kretprobe,
+ NULL, &kprobe_opts);
+ if (!ASSERT_OK_PTR(skel->links.handle_kretprobe,
+ "attach_kretprobe_by_addr"))
+ goto cleanup;
+
+ /* trigger & validate kprobe && kretprobe */
+ usleep(1);
+
+ ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res");
+ ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res");
+
+cleanup:
+ test_attach_probe_manual__destroy(skel);
+}
+
+/* reject legacy address-based kprobe attach */
+static void test_attach_kprobe_legacy_by_addr_reject(void)
+{
+ DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, kprobe_opts);
+ struct test_attach_probe_manual *skel;
+ unsigned long func_addr;
+
+ if (!ASSERT_OK(load_kallsyms(), "load_kallsyms"))
+ return;
+
+ func_addr = ksym_get_addr(SYS_NANOSLEEP_KPROBE_NAME);
+ if (!ASSERT_NEQ(func_addr, 0UL, "func_addr"))
+ return;
+
+ skel = test_attach_probe_manual__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_kprobe_manual_open_and_load"))
+ return;
+
+ kprobe_opts.attach_mode = PROBE_ATTACH_MODE_LEGACY;
+ kprobe_opts.offset = func_addr;
+ skel->links.handle_kprobe =
+ bpf_program__attach_kprobe_opts(skel->progs.handle_kprobe,
+ NULL, &kprobe_opts);
+ if (ASSERT_ERR_PTR(skel->links.handle_kprobe,
+ "attach_kprobe_legacy_by_addr"))
+ ASSERT_EQ(libbpf_get_error(skel->links.handle_kprobe), -ENOTSUP,
+ "attach_kprobe_legacy_by_addr_err");
+
+ test_attach_probe_manual__destroy(skel);
+}
+
/* attach uprobe/uretprobe long event name testings */
static void test_attach_uprobe_long_event_name(void)
{
@@ -416,6 +492,12 @@ void test_attach_probe(void)
test_attach_probe_manual(PROBE_ATTACH_MODE_PERF);
if (test__start_subtest("manual-link"))
test_attach_probe_manual(PROBE_ATTACH_MODE_LINK);
+ if (test__start_subtest("kprobe-perf-by-addr"))
+ test_attach_kprobe_by_addr(PROBE_ATTACH_MODE_PERF);
+ if (test__start_subtest("kprobe-link-by-addr"))
+ test_attach_kprobe_by_addr(PROBE_ATTACH_MODE_LINK);
+ if (test__start_subtest("kprobe-legacy-by-addr-reject"))
+ test_attach_kprobe_legacy_by_addr_reject();
if (test__start_subtest("auto"))
test_attach_probe_auto(skel);
--
2.52.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-31 9:41 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-31 9:37 [PATCH bpf-next v3 0/2] libbpf: clarify raw-address single kprobe attach behavior Hoyeon Lee
2026-03-31 9:37 ` [PATCH bpf-next v3 1/2] " Hoyeon Lee
2026-03-31 9:37 ` [PATCH bpf-next v3 2/2] selftests/bpf: add test for raw-address single kprobe attach Hoyeon Lee
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®