Re: [PATCH v14 03/14] kprobes: Protect kprobe_blacklist with RCU

From: Google

Date: Tue Sep 01 2026 - 21:31:02 EST


On Sun, 30 Aug 2026 23:27:23 +0900
"Masami Hiramatsu (Google)" <mhiramat@xxxxxxxxxx> wrote:

> From: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
>
> __within_kprobe_blacklist() traverses kprobe_blacklist without holding
> kprobe_mutex. When a module is unloaded, kprobe_remove_area_blacklist()
> removes blacklist entries and immediately frees them with kfree().
> A concurrent call to within_kprobe_blacklist() can therefore dereference
> freed memory.
>
> Furthermore, within_kprobe_blacklist() can be called in atomic or
> non-preemptible contexts where the sleeping kprobe_mutex cannot be taken.
>
> Protect kprobe_blacklist with RCU. Use guard(rcu)() and
> list_for_each_entry_rcu() for traversal, list_add_tail_rcu() for
> insertions, list_del_rcu() for deletions, and kfree_rcu() to reclaim
> entries safely after a grace period.

I realized this is required even without wprobe. So let me take this
as a stable fix with following tags.

Fixes: 376e242429bf ("kprobes: Introduce NOKPROBE_SYMBOL() macro to maintain kprobes blacklist")
Cc: stable@xxxxxxxxxxxxxxx
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://lore.kernel.org/all/20260807155802.F06041F000E9@xxxxxxxxxxxxxxx/

Thanks,

>
> Assisted-by: Antigravity:gemini-3.7-flash
> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
> ---
> Changes in v13:
> - Newly added.
> ---
> include/linux/kprobes.h | 1 +
> kernel/kprobes.c | 14 ++++++++++----
> 2 files changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
> index 8c4f3bb24429..e6de7ae55bda 100644
> --- a/include/linux/kprobes.h
> +++ b/include/linux/kprobes.h
> @@ -181,6 +181,7 @@ struct kprobe_blacklist_entry {
> struct list_head list;
> unsigned long start_addr;
> unsigned long end_addr;
> + struct rcu_head rcu;
> };
>
> #ifdef CONFIG_KPROBES
> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> index bfc89083daa9..6337da5cab9e 100644
> --- a/kernel/kprobes.c
> +++ b/kernel/kprobes.c
> @@ -1447,8 +1447,14 @@ static bool __within_kprobe_blacklist(unsigned long addr)
> /*
> * If 'kprobe_blacklist' is defined, check the address and
> * reject any probe registration in the prohibited area.
> + * Note: this can return true during transition period where
> + * (start_addr, end_addr) in the black list is shrinking
> + * but old entry has not been removed yet. This is acceptable
> + * because the worst case is that we reject more probes than
> + * we should.
> */
> - list_for_each_entry(ent, &kprobe_blacklist, list) {
> + guard(rcu)();
> + list_for_each_entry_rcu(ent, &kprobe_blacklist, list) {
> if (addr >= ent->start_addr && addr < ent->end_addr)
> return true;
> }
> @@ -2509,7 +2515,7 @@ int kprobe_add_ksym_blacklist(unsigned long entry)
> ent->start_addr = entry;
> ent->end_addr = entry + size;
> INIT_LIST_HEAD(&ent->list);
> - list_add_tail(&ent->list, &kprobe_blacklist);
> + list_add_tail_rcu(&ent->list, &kprobe_blacklist);
>
> return (int)size;
> }
> @@ -2603,8 +2609,8 @@ static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
> list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
> if (ent->start_addr < start || ent->start_addr >= end)
> continue;
> - list_del(&ent->list);
> - kfree(ent);
> + list_del_rcu(&ent->list);
> + kfree_rcu(ent, rcu);
> }
> }
>
>


--
Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>