From: Jianpeng Chang <jianpeng.chang.cn@windriver.com>
To: <naveen@kernel.org>, <davem@davemloft.net>, <mhiramat@kernel.org>,
<catalin.marinas@arm.com>, <mark.rutland@arm.com>
Cc: <linux-kernel@vger.kernel.org>,
<linux-trace-kernel@vger.kernel.org>, <stable@vger.kernel.org>,
Jianpeng Chang <jianpeng.chang.cn@windriver.com>
Subject: [PATCH] kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist()
Date: Mon, 27 Apr 2026 15:35:44 +0800 [thread overview]
Message-ID: <20260427073545.3656835-1-jianpeng.chang.cn@windriver.com> (raw)
When kprobe_add_area_blacklist() iterates through a section like
.kprobes.text, the start address may not correspond to a named symbol.
On ARM64 with CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y (introduced by
commit baaf553d3bc3 ("arm64: Implement
HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS")), the compiler flag
-fpatchable-function-entry=4,2 inserts 2 NOPs before each function entry
point for ftrace call_ops. These pre-function NOPs sit at the section base
address, before the first named function symbol. The compiler emits a $x
mapping symbol at offset 0x00 to mark the start of code, but
find_kallsyms_symbol() ignores mapping symbols.
Without CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS (e.g. defconfig), no
pre-function NOPs are inserted, the first function starts at offset
0x00, and the bug does not trigger.
This only affects modules that have a .kprobes.text section (i.e. those
using the __kprobes annotation). Modules using NOKPROBE_SYMBOL() instead
(like kretprobe_example.ko) blacklist exact function addresses via the
_kprobe_blacklist section and are not affected.
For kprobe_example.ko on ARM64 with -fpatchable-function-entry=4,2,
the .kprobes.text section layout is:
offset 0x00: $x + 2 NOPs (mapping symbol + ftrace preamble)
offset 0x08: handler_post (64 bytes)
offset 0x50: handler_pre (68 bytes)
kprobe_add_area_blacklist() starts iterating from the section base
address (offset 0x00), which only has the $x mapping symbol.
kprobe_add_ksym_blacklist() then calls kallsyms_lookup_size_offset()
for this address, which goes through:
kallsyms_lookup_size_offset()
-> module_address_lookup()
-> find_kallsyms_symbol()
find_kallsyms_symbol() scans all module symbols to find the closest
preceding symbol.
Since no named text symbol exists at offset 0x00,
find_kallsyms_symbol() picks __UNIQUE_ID_vermagic (a .modinfo symbol
whose address is in the temporary image) as the "best" match. The
computed "size" = next_text_symbol - modinfo_symbol spans across
these two unrelated memory regions, creating a blacklist entry with
a bogus range of tens of terabytes.
Whether this causes a visible failure depends on address randomization,
here is what happens on Raspberry Pi 4/5:
- On RPi5, the bogus size was ~35 TB. start + size stayed within
64-bit range, so the blacklist entry covered the entire kernel
text. register_kprobe() in the module's own init function failed
with -EINVAL.
- On RPi4, the bogus size was ~75 TB. start + size overflowed
64 bits and wrapped to a small address near zero. The range
check (addr >= start && addr < end) then failed because end
wrapped around, so the bogus entry was accidentally harmless
and kprobes worked by luck.
The same bug exists on both machines, but randomization determines whether
the integer overflow masks it or not.
Fix this by checking the offset returned by kallsyms_lookup_size_offset().
A non-zero offset means the address is not at a symbol boundary, so skip
forward to the next symbol instead of creating a blacklist entry with a
wrong size.
Fixes: baaf553d3bc3 ("arm64: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS")
Signed-off-by: Jianpeng Chang <jianpeng.chang.cn@windriver.com>
---
Hi,
This patch skips non-symbol addresses, fixes the bogus blacklist entry,
but leaves the NOP gap at the start of .kprobes.text unblacklisted.
We can continue alloc the ent without return to add the gap to
blacklist, or do some more works to add the gap to the first symbol in
blacklist. I'm not sure if is this necessary, or is there a better way?
Thanks,
Jianpeng
kernel/kprobes.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index bfc89083daa9..be700fb03198 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -2503,6 +2503,10 @@ int kprobe_add_ksym_blacklist(unsigned long entry)
!kallsyms_lookup_size_offset(entry, &size, &offset))
return -EINVAL;
+ /* Not on a symbol boundary -- skip to the next symbol */
+ if (offset)
+ return (int)(size - offset);
+
ent = kmalloc_obj(*ent);
if (!ent)
return -ENOMEM;
--
2.54.0
next reply other threads:[~2026-04-27 7:36 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-27 7:35 Jianpeng Chang [this message]
2026-04-28 9:43 ` [PATCH] kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist() Masami Hiramatsu
2026-04-29 8:16 ` Jianpeng Chang
2026-04-29 8:30 ` Masami Hiramatsu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260427073545.3656835-1-jianpeng.chang.cn@windriver.com \
--to=jianpeng.chang.cn@windriver.com \
--cc=catalin.marinas@arm.com \
--cc=davem@davemloft.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mhiramat@kernel.org \
--cc=naveen@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox