* [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary
@ 2026-08-24 9:28 Jiayuan Chen
2026-08-24 9:28 ` [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10 Jiayuan Chen
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Jiayuan Chen @ 2026-08-24 9:28 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Jakub Sitnicki,
Peter Zijlstra (Intel), Jiawei Zhao, linux-kernel,
linux-kselftest
The kernel refuses to attach to a nop10 that crosses a page boundary,
since it can't be atomically rewritten:
/* can_optimize(), arch/x86/kernel/uprobes.c */
/* We can't do cross page atomic writes yet. */
return PAGE_SIZE - (vaddr & ~PAGE_MASK) >= OPT_INSN_SIZE;
Whether the nop10 crosses a page is purely up to the binary layout, so
this does happen in practice. libbpf doesn't check for it and blindly
shifts the uprobe onto the nop10, and the attach then fails with
-ENOTSUPP. Just keep the uprobe on the preceding 1-byte nop in that
case, it works everywhere as a regular int3 uprobe.
Fixes: 41a5c7df4466 ("libbpf: Add support to detect nop,nop5 instructions combo for usdt probe")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
tools/lib/bpf/usdt.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
index 2e56e3ab5b6c..c266ac93cbdd 100644
--- a/tools/lib/bpf/usdt.c
+++ b/tools/lib/bpf/usdt.c
@@ -614,11 +614,28 @@ static bool has_nop_combo(int fd, long off)
return false;
return memcmp(buf, nop_combo, 11) == 0;
}
+
+/*
+ * The kernel refuses to attach to a nop10 that crosses a page boundary,
+ * as it can't be atomically rewritten. Page offset of the probe is the
+ * same in the file and in any mapping, so this can be checked statically.
+ */
+static bool nop10_within_page(long off)
+{
+ long page_sz = getpagesize();
+
+ return off % page_sz + 10 <= page_sz;
+}
#else
static bool has_nop_combo(int fd, long off)
{
return false;
}
+
+static bool nop10_within_page(long off)
+{
+ return false;
+}
#endif
static int collect_usdt_targets(struct usdt_manager *man, struct elf_fd *elf_fd, const char *path,
@@ -827,9 +844,11 @@ static int collect_usdt_targets(struct usdt_manager *man, struct elf_fd *elf_fd,
/*
* We have uprobe syscall and usdt with nop,nop10 instructions combo,
* so we can place the uprobe directly on nop10 (+1) and get this probe
- * optimized.
+ * optimized. If the nop10 crosses a page boundary, keep the uprobe
+ * on the preceding 1-byte nop, which the kernel accepts everywhere.
*/
- if (man->has_uprobe_syscall && has_nop_combo(elf_fd->fd, usdt_rel_ip)) {
+ if (man->has_uprobe_syscall && has_nop_combo(elf_fd->fd, usdt_rel_ip) &&
+ nop10_within_page(usdt_rel_ip + 1)) {
usdt_abs_ip++;
usdt_rel_ip++;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10
2026-08-24 9:28 [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary Jiayuan Chen
@ 2026-08-24 9:28 ` Jiayuan Chen
2026-08-24 10:03 ` bot+bpf-ci
2026-08-24 10:03 ` [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary bot+bpf-ci
2026-08-25 13:58 ` Jiri Olsa
2 siblings, 1 reply; 8+ messages in thread
From: Jiayuan Chen @ 2026-08-24 9:28 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Ihor Solodrai, Shuah Khan,
Peter Zijlstra (Intel), Jakub Sitnicki, Jiawei Zhao, linux-kernel,
linux-kselftest
Add a USDT probe laid out so that its nop10 crosses a page boundary
and check that attaching to it succeeds and the probe fires. Without
the previous fix libbpf shifts the uprobe onto the nop10 and the
attach fails with -ENOTSUPP.
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
tools/testing/selftests/bpf/prog_tests/usdt.c | 54 +++++++++++++++++++
tools/testing/selftests/bpf/usdt_2.c | 16 ++++++
2 files changed, 70 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/usdt.c b/tools/testing/selftests/bpf/prog_tests/usdt.c
index 8004c9568ffa..eff1e57ab13c 100644
--- a/tools/testing/selftests/bpf/prog_tests/usdt.c
+++ b/tools/testing/selftests/bpf/prog_tests/usdt.c
@@ -250,6 +250,7 @@ static void subtest_basic_usdt(bool optimized)
#ifdef __x86_64__
extern void usdt_1(void);
extern void usdt_2(void);
+extern void usdt_2_cross_page(void);
extern void usdt_red_zone_trigger(void);
static unsigned char nop1[1] = { 0x90 };
@@ -342,6 +343,57 @@ static void subtest_optimized_attach(void)
test_usdt__destroy(skel);
}
+/*
+ * Test attachment to a USDT probe whose nop10 crosses a page boundary.
+ * The kernel can't optimize such nop10, so libbpf keeps the uprobe on
+ * the preceding 1-byte nop. Do not assume any particular placement
+ * here, though: however the probe ends up attached, the attachment
+ * must succeed and the probe must fire.
+ */
+static void subtest_optimized_attach_cross_page(void)
+{
+ long page_sz = sysconf(_SC_PAGESIZE);
+ struct test_usdt *skel;
+ __u8 *addr = NULL;
+ long i;
+
+ /* combo is placed up to a page of padding after the function start */
+ for (i = 0; i < 2 * page_sz; i++) {
+ if (!memcmp((void *)usdt_2_cross_page + i, nop1_nop10_combo, 11)) {
+ addr = (void *)usdt_2_cross_page + i;
+ break;
+ }
+ }
+ if (!ASSERT_OK_PTR(addr, "find_nop1_nop10_combo"))
+ return;
+
+ /* layout sanity check: the nop10 must cross the page boundary */
+ if (!ASSERT_GT((unsigned long)(addr + 1) % page_sz + 10, page_sz,
+ "nop10_crosses_page"))
+ return;
+
+ skel = test_usdt__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "test_usdt__open_and_load"))
+ return;
+
+ skel->bss->my_pid = getpid();
+
+ skel->links.usdt0 = bpf_program__attach_usdt(skel->progs.usdt0,
+ 0 /*self*/, "/proc/self/exe",
+ "optimized_attach",
+ "usdt_2_cross_page", NULL);
+ if (!ASSERT_OK_PTR(skel->links.usdt0, "bpf_program__attach_usdt"))
+ goto cleanup;
+
+ usdt_2_cross_page();
+ usdt_2_cross_page();
+
+ ASSERT_EQ(skel->bss->usdt0_called, 2, "usdt0_called");
+
+cleanup:
+ test_usdt__destroy(skel);
+}
+
/*
* Test that USDT arguments survive nop10 optimization in a function where
* the compiler places operands in the red zone.
@@ -660,6 +712,8 @@ void test_usdt(void)
subtest_basic_usdt(true);
if (test__start_subtest("optimized_attach"))
subtest_optimized_attach();
+ if (test__start_subtest("optimized_attach_cross_page"))
+ subtest_optimized_attach_cross_page();
if (test__start_subtest("optimized_red_zone"))
subtest_optimized_red_zone();
#endif
diff --git a/tools/testing/selftests/bpf/usdt_2.c b/tools/testing/selftests/bpf/usdt_2.c
index 5e38f8605b02..3b7024b9b08b 100644
--- a/tools/testing/selftests/bpf/usdt_2.c
+++ b/tools/testing/selftests/bpf/usdt_2.c
@@ -13,6 +13,22 @@ void usdt_2(void)
USDT(optimized_attach, usdt_2);
}
+/*
+ * Force the nop1,nop10 combo of the USDT probe to a spot where the nop10
+ * crosses a page boundary: .balign starts the padding exactly at a page
+ * start regardless of the compiler-generated prologue size, and the 4086
+ * one-byte nops put the nop1 at page offset 4086, so the following nop10
+ * occupies the last 9 bytes of that page and 1 byte of the next one.
+ * The kernel can't optimize such nop10, so libbpf must keep the uprobe
+ * on the 1-byte nop.
+ */
+__attribute__((noinline))
+void usdt_2_cross_page(void)
+{
+ asm volatile (".balign 4096, 0x90\n\t.skip 4086, 0x90");
+ USDT(optimized_attach, usdt_2_cross_page);
+}
+
static volatile unsigned long usdt_red_zone_arg1 = 0xDEADBEEF;
static volatile unsigned long usdt_red_zone_arg2 = 0xCAFEBABE;
static volatile unsigned long usdt_red_zone_arg3 = 0xFEEDFACE;
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary
2026-08-24 9:28 [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary Jiayuan Chen
2026-08-24 9:28 ` [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10 Jiayuan Chen
@ 2026-08-24 10:03 ` bot+bpf-ci
2026-08-24 10:27 ` Jiayuan Chen
2026-08-25 13:58 ` Jiri Olsa
2 siblings, 1 reply; 8+ messages in thread
From: bot+bpf-ci @ 2026-08-24 10:03 UTC (permalink / raw)
To: jiayuan.chen, bpf
Cc: jiayuan.chen, ast, daniel, andrii, eddyz87, memxor, martin.lau,
song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, jakub,
peterz, phoenix500526, linux-kernel, linux-kselftest, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2019 bytes --]
> Fixes: 41a5c7df4466 ("libbpf: Add support to detect nop,nop5 instructions combo for usdt probe")
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Does the Fixes tag point at the right commit? The -ENOTSUPP attach
failure could not happen at 41a5c7df4466.
At 41a5c7df4466 the uprobe was shifted onto a nop5 (0f 1f 44 00 00), and
arch_uprobe_analyze_insn() ran uprobe_init_insn() unconditionally:
ret = uprobe_init_insn(auprobe, &insn, is_64bit_mm(mm));
if (ret)
return ret;
if (can_optimize(&insn, addr))
set_bit(ARCH_UPROBE_FLAG_CAN_OPTIMIZE, &auprobe->flags);
uprobe_init_insn() accepts nop5: is_prefix_bad() finds no prefix, and
test_bit(OPCODE1 == 0x0f, good_insns_64) is set. So a nop5 that crossed
a page boundary simply produced a normal, working int3 uprobe. The attach
succeeded.
The failure was introduced by the nop10 switch:
554ba38456da ("uprobes/x86: Move optimized uprobe from nop5 to nop10")
made can_optimize() failure fall through to uprobe_init_insn(), and the
nop10's 0x2e byte is a CS prefix that is_prefix_bad() rejects:
if (can_optimize(&insn, addr)) {
set_bit(ARCH_UPROBE_FLAG_CAN_OPTIMIZE, &auprobe->flags);
} else {
ret = uprobe_init_insn(auprobe, &insn);
if (ret)
return ret;
}
ee2862439e5c ("libbpf: Change has_nop_combo to work on top of nop10")
made libbpf shift the uprobe onto that nop10.
Should the tag be:
Fixes: ee2862439e5c ("libbpf: Change has_nop_combo to work on top of nop10")
This also matters for backport scope: a tree that has 41a5c7df4466 but
not ee2862439e5c still matches the 6-byte nop,nop5 pattern, where the
new hardcoded +10 in nop10_within_page() would be over-strict by 5 bytes
while the bug being fixed does not exist there.
---
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/32712703327
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10
2026-08-24 9:28 ` [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10 Jiayuan Chen
@ 2026-08-24 10:03 ` bot+bpf-ci
0 siblings, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-08-24 10:03 UTC (permalink / raw)
To: jiayuan.chen, bpf
Cc: jiayuan.chen, ast, daniel, andrii, eddyz87, memxor, martin.lau,
song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, peterz,
jakub, phoenix500526, linux-kernel, linux-kselftest, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2796 bytes --]
> diff --git a/tools/testing/selftests/bpf/prog_tests/usdt.c b/tools/testing/selftests/bpf/prog_tests/usdt.c
> index 8004c9568ffa..eff1e57ab13c 100644
> --- a/tools/testing/selftests/bpf/prog_tests/usdt.c
> +++ b/tools/testing/selftests/bpf/prog_tests/usdt.c
[ ... ]
> @@ -342,6 +343,57 @@ static void subtest_optimized_attach(void)
> test_usdt__destroy(skel);
> }
>
> +/*
> + * Test attachment to a USDT probe whose nop10 crosses a page boundary.
> + * The kernel can't optimize such nop10, so libbpf keeps the uprobe on
> + * the preceding 1-byte nop. Do not assume any particular placement
> + * here, though: however the probe ends up attached, the attachment
> + * must succeed and the probe must fire.
> + */
> +static void subtest_optimized_attach_cross_page(void)
> +{
> + long page_sz = sysconf(_SC_PAGESIZE);
> + struct test_usdt *skel;
> + __u8 *addr = NULL;
> + long i;
> +
> + /* combo is placed up to a page of padding after the function start */
> + for (i = 0; i < 2 * page_sz; i++) {
This isn't a bug, but should the comment say up to two pages to match the
2 * page_sz scan bound? With the .balign 4096 fill plus the 4086-byte
.skip in usdt_2_cross_page(), the combo can land roughly 8150 bytes past
the function start when the compiler emits a prologue.
> + if (!memcmp((void *)usdt_2_cross_page + i, nop1_nop10_combo, 11)) {
This isn't a bug, but could find_instr() take a search range so this
subtest reuses it rather than open-coding the same memcmp scan?
find_instr() already implements this loop a hundred lines above, only
with a hardcoded 10-byte window instead of 2 * page_sz.
> + addr = (void *)usdt_2_cross_page + i;
> + break;
> + }
> + }
> + if (!ASSERT_OK_PTR(addr, "find_nop1_nop10_combo"))
> + return;
> +
> + /* layout sanity check: the nop10 must cross the page boundary */
> + if (!ASSERT_GT((unsigned long)(addr + 1) % page_sz + 10, page_sz,
> + "nop10_crosses_page"))
> + return;
> +
> + skel = test_usdt__open_and_load();
> + if (!ASSERT_OK_PTR(skel, "test_usdt__open_and_load"))
> + return;
> +
> + skel->bss->my_pid = getpid();
> +
> + skel->links.usdt0 = bpf_program__attach_usdt(skel->progs.usdt0,
> + 0 /*self*/, "/proc/self/exe",
> + "optimized_attach",
> + "usdt_2_cross_page", NULL);
> + if (!ASSERT_OK_PTR(skel->links.usdt0, "bpf_program__attach_usdt"))
> + goto cleanup;
> +
> + usdt_2_cross_page();
> + usdt_2_cross_page();
> +
> + ASSERT_EQ(skel->bss->usdt0_called, 2, "usdt0_called");
> +
> +cleanup:
> + test_usdt__destroy(skel);
> +}
[ ... ]
---
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/32712703327
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary
2026-08-24 10:03 ` [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary bot+bpf-ci
@ 2026-08-24 10:27 ` Jiayuan Chen
0 siblings, 0 replies; 8+ messages in thread
From: Jiayuan Chen @ 2026-08-24 10:27 UTC (permalink / raw)
To: bot+bpf-ci, bpf
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, ihor.solodrai, shuah, jakub, peterz,
phoenix500526, linux-kernel, linux-kselftest, martin.lau, clm
On 8/24/26 6:03 PM, bot+bpf-ci@kernel.org wrote:
>> Fixes: 41a5c7df4466 ("libbpf: Add support to detect nop,nop5 instructions combo for usdt probe")
>> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
> Does the Fixes tag point at the right commit? The -ENOTSUPP attach
> failure could not happen at 41a5c7df4466.
>
> At 41a5c7df4466 the uprobe was shifted onto a nop5 (0f 1f 44 00 00), and
> arch_uprobe_analyze_insn() ran uprobe_init_insn() unconditionally:
>
> ret = uprobe_init_insn(auprobe, &insn, is_64bit_mm(mm));
> if (ret)
> return ret;
> if (can_optimize(&insn, addr))
> set_bit(ARCH_UPROBE_FLAG_CAN_OPTIMIZE, &auprobe->flags);
>
> uprobe_init_insn() accepts nop5: is_prefix_bad() finds no prefix, and
> test_bit(OPCODE1 == 0x0f, good_insns_64) is set. So a nop5 that crossed
> a page boundary simply produced a normal, working int3 uprobe. The attach
> succeeded.
>
> The failure was introduced by the nop10 switch:
>
> 554ba38456da ("uprobes/x86: Move optimized uprobe from nop5 to nop10")
> made can_optimize() failure fall through to uprobe_init_insn(), and the
> nop10's 0x2e byte is a CS prefix that is_prefix_bad() rejects:
>
> if (can_optimize(&insn, addr)) {
> set_bit(ARCH_UPROBE_FLAG_CAN_OPTIMIZE, &auprobe->flags);
> } else {
> ret = uprobe_init_insn(auprobe, &insn);
> if (ret)
> return ret;
> }
>
> ee2862439e5c ("libbpf: Change has_nop_combo to work on top of nop10")
> made libbpf shift the uprobe onto that nop10.
>
> Should the tag be:
>
> Fixes: ee2862439e5c ("libbpf: Change has_nop_combo to work on top of nop10")
ee2862439e5c is correct.
Waiting for more feedback.
> This also matters for backport scope: a tree that has 41a5c7df4466 but
> not ee2862439e5c still matches the 6-byte nop,nop5 pattern, where the
> new hardcoded +10 in nop10_within_page() would be over-strict by 5 bytes
> while the bug being fixed does not exist there.
>
>
>
> ---
> 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/32712703327
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary
2026-08-24 9:28 [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary Jiayuan Chen
2026-08-24 9:28 ` [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10 Jiayuan Chen
2026-08-24 10:03 ` [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary bot+bpf-ci
@ 2026-08-25 13:58 ` Jiri Olsa
2026-08-25 14:29 ` Jiayuan Chen
2 siblings, 1 reply; 8+ messages in thread
From: Jiri Olsa @ 2026-08-25 13:58 UTC (permalink / raw)
To: Jiayuan Chen
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Emil Tsalapatis, Ihor Solodrai,
Shuah Khan, Jakub Sitnicki, Peter Zijlstra (Intel), Jiawei Zhao,
linux-kernel, linux-kselftest
On Mon, Aug 24, 2026 at 05:28:36PM +0800, Jiayuan Chen wrote:
> The kernel refuses to attach to a nop10 that crosses a page boundary,
> since it can't be atomically rewritten:
>
> /* can_optimize(), arch/x86/kernel/uprobes.c */
> /* We can't do cross page atomic writes yet. */
> return PAGE_SIZE - (vaddr & ~PAGE_MASK) >= OPT_INSN_SIZE;
>
> Whether the nop10 crosses a page is purely up to the binary layout, so
> this does happen in practice. libbpf doesn't check for it and blindly
> shifts the uprobe onto the nop10, and the attach then fails with
> -ENOTSUPP. Just keep the uprobe on the preceding 1-byte nop in that
> case, it works everywhere as a regular int3 uprobe.
>
> Fixes: 41a5c7df4466 ("libbpf: Add support to detect nop,nop5 instructions combo for usdt probe")
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
> ---
> tools/lib/bpf/usdt.c | 23 +++++++++++++++++++++--
> 1 file changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
> index 2e56e3ab5b6c..c266ac93cbdd 100644
> --- a/tools/lib/bpf/usdt.c
> +++ b/tools/lib/bpf/usdt.c
> @@ -614,11 +614,28 @@ static bool has_nop_combo(int fd, long off)
> return false;
> return memcmp(buf, nop_combo, 11) == 0;
> }
> +
> +/*
> + * The kernel refuses to attach to a nop10 that crosses a page boundary,
> + * as it can't be atomically rewritten. Page offset of the probe is the
> + * same in the file and in any mapping, so this can be checked statically.
> + */
> +static bool nop10_within_page(long off)
> +{
> + long page_sz = getpagesize();
> +
> + return off % page_sz + 10 <= page_sz;
could this be another check in has_nop_combo ? so we do not
need to introduce another stub
otherwise lgtm, thanks
jirka
> +}
> #else
> static bool has_nop_combo(int fd, long off)
> {
> return false;
> }
> +
> +static bool nop10_within_page(long off)
> +{
> + return false;
> +}
> #endif
>
> static int collect_usdt_targets(struct usdt_manager *man, struct elf_fd *elf_fd, const char *path,
> @@ -827,9 +844,11 @@ static int collect_usdt_targets(struct usdt_manager *man, struct elf_fd *elf_fd,
> /*
> * We have uprobe syscall and usdt with nop,nop10 instructions combo,
> * so we can place the uprobe directly on nop10 (+1) and get this probe
> - * optimized.
> + * optimized. If the nop10 crosses a page boundary, keep the uprobe
> + * on the preceding 1-byte nop, which the kernel accepts everywhere.
> */
> - if (man->has_uprobe_syscall && has_nop_combo(elf_fd->fd, usdt_rel_ip)) {
> + if (man->has_uprobe_syscall && has_nop_combo(elf_fd->fd, usdt_rel_ip) &&
> + nop10_within_page(usdt_rel_ip + 1)) {
> usdt_abs_ip++;
> usdt_rel_ip++;
> }
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary
2026-08-25 13:58 ` Jiri Olsa
@ 2026-08-25 14:29 ` Jiayuan Chen
2026-08-25 18:32 ` Andrii Nakryiko
0 siblings, 1 reply; 8+ messages in thread
From: Jiayuan Chen @ 2026-08-25 14:29 UTC (permalink / raw)
To: Jiri Olsa
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Emil Tsalapatis, Ihor Solodrai,
Shuah Khan, Jakub Sitnicki, Peter Zijlstra (Intel), Jiawei Zhao,
linux-kernel, linux-kselftest
On 8/25/26 9:58 PM, Jiri Olsa wrote:
> On Mon, Aug 24, 2026 at 05:28:36PM +0800, Jiayuan Chen wrote:
>> The kernel refuses to attach to a nop10 that crosses a page boundary,
>> since it can't be atomically rewritten:
>>
>> /* can_optimize(), arch/x86/kernel/uprobes.c */
>> /* We can't do cross page atomic writes yet. */
>> return PAGE_SIZE - (vaddr & ~PAGE_MASK) >= OPT_INSN_SIZE;
>>
>> Whether the nop10 crosses a page is purely up to the binary layout, so
>> this does happen in practice. libbpf doesn't check for it and blindly
>> shifts the uprobe onto the nop10, and the attach then fails with
>> -ENOTSUPP. Just keep the uprobe on the preceding 1-byte nop in that
>> case, it works everywhere as a regular int3 uprobe.
>>
>> Fixes: 41a5c7df4466 ("libbpf: Add support to detect nop,nop5 instructions combo for usdt probe")
>> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
>> ---
>> tools/lib/bpf/usdt.c | 23 +++++++++++++++++++++--
>> 1 file changed, 21 insertions(+), 2 deletions(-)
>>
>> diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
>> index 2e56e3ab5b6c..c266ac93cbdd 100644
>> --- a/tools/lib/bpf/usdt.c
>> +++ b/tools/lib/bpf/usdt.c
>> @@ -614,11 +614,28 @@ static bool has_nop_combo(int fd, long off)
>> return false;
>> return memcmp(buf, nop_combo, 11) == 0;
>> }
>> +
>> +/*
>> + * The kernel refuses to attach to a nop10 that crosses a page boundary,
>> + * as it can't be atomically rewritten. Page offset of the probe is the
>> + * same in the file and in any mapping, so this can be checked statically.
>> + */
>> +static bool nop10_within_page(long off)
>> +{
>> + long page_sz = getpagesize();
>> +
>> + return off % page_sz + 10 <= page_sz;
> could this be another check in has_nop_combo ? so we do not
> need to introduce another stub
>
> otherwise lgtm, thanks
>
> jirka
>
Thanks Jirka
Sound reasonable, I will do it.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary
2026-08-25 14:29 ` Jiayuan Chen
@ 2026-08-25 18:32 ` Andrii Nakryiko
0 siblings, 0 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2026-08-25 18:32 UTC (permalink / raw)
To: Jiayuan Chen
Cc: Jiri Olsa, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Emil Tsalapatis,
Ihor Solodrai, Shuah Khan, Jakub Sitnicki, Peter Zijlstra (Intel),
Jiawei Zhao, linux-kernel, linux-kselftest
On Tue, Aug 25, 2026 at 7:29 AM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
>
> On 8/25/26 9:58 PM, Jiri Olsa wrote:
> > On Mon, Aug 24, 2026 at 05:28:36PM +0800, Jiayuan Chen wrote:
> >> The kernel refuses to attach to a nop10 that crosses a page boundary,
> >> since it can't be atomically rewritten:
> >>
> >> /* can_optimize(), arch/x86/kernel/uprobes.c */
> >> /* We can't do cross page atomic writes yet. */
> >> return PAGE_SIZE - (vaddr & ~PAGE_MASK) >= OPT_INSN_SIZE;
> >>
> >> Whether the nop10 crosses a page is purely up to the binary layout, so
> >> this does happen in practice. libbpf doesn't check for it and blindly
> >> shifts the uprobe onto the nop10, and the attach then fails with
> >> -ENOTSUPP. Just keep the uprobe on the preceding 1-byte nop in that
> >> case, it works everywhere as a regular int3 uprobe.
> >>
> >> Fixes: 41a5c7df4466 ("libbpf: Add support to detect nop,nop5 instructions combo for usdt probe")
> >> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
> >> ---
> >> tools/lib/bpf/usdt.c | 23 +++++++++++++++++++++--
> >> 1 file changed, 21 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
> >> index 2e56e3ab5b6c..c266ac93cbdd 100644
> >> --- a/tools/lib/bpf/usdt.c
> >> +++ b/tools/lib/bpf/usdt.c
> >> @@ -614,11 +614,28 @@ static bool has_nop_combo(int fd, long off)
> >> return false;
> >> return memcmp(buf, nop_combo, 11) == 0;
> >> }
> >> +
> >> +/*
> >> + * The kernel refuses to attach to a nop10 that crosses a page boundary,
> >> + * as it can't be atomically rewritten. Page offset of the probe is the
> >> + * same in the file and in any mapping, so this can be checked statically.
> >> + */
> >> +static bool nop10_within_page(long off)
> >> +{
> >> + long page_sz = getpagesize();
> >> +
> >> + return off % page_sz + 10 <= page_sz;
> > could this be another check in has_nop_combo ? so we do not
> > need to introduce another stub
I'd go a step further and collapse three checks, including
man->has_uprobe_syscall, into a single "can we do uprobe nop
optimization" function?
> >
> > otherwise lgtm, thanks
> >
> > jirka
> >
> Thanks Jirka
>
> Sound reasonable, I will do it.
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-25 18:33 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 9:28 [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary Jiayuan Chen
2026-08-24 9:28 ` [PATCH bpf 2/2] selftests/bpf: Add test for usdt probe with page-crossing nop10 Jiayuan Chen
2026-08-24 10:03 ` bot+bpf-ci
2026-08-24 10:03 ` [PATCH bpf 1/2] libbpf: Fix usdt attach failure when nop10 crosses page boundary bot+bpf-ci
2026-08-24 10:27 ` Jiayuan Chen
2026-08-25 13:58 ` Jiri Olsa
2026-08-25 14:29 ` Jiayuan Chen
2026-08-25 18:32 ` Andrii Nakryiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox