From: sashiko-bot@kernel.org
To: "Andi Kleen" <ak@kernel.org>
Cc: linux-trace-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org
Subject: Re: [RFC PATCH v2 02/11] ptwrite uprobes: Add minimal low level support for x86
Date: Thu, 17 Sep 2026 23:25:19 +0000 [thread overview]
Message-ID: <20260917232520.341AD1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260917230127.924985-3-ak@kernel.org>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] x86/uprobes: Uninitialized variable first_phase_done causes invalid fallback
- [High] x86/uprobes: Missing __GFP_ACCOUNT bypasses memcg and GFP_KERNEL deadlocks
- [Medium] x86/uprobes: GFP_HIGHUSER allocation pins unmigratable pages in movable zones
--
commit 692de39e6024ec893235089efa2253699ad076bf
Author: Andi Kleen <ak@kernel.org>
ptwrite uprobes: Add minimal low level support for x86
Add more data structures and the x86 machinery to generate the PTWRITE
instructions for a ptwrite uprobe. The probe executes PTWRITEs and then
jumps back to the original code. In this variant only patching
5 byte nops is supported.
> diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
> index 65a2de82ecd29..7fcdc4bf5197a 100644
> --- a/arch/x86/kernel/uprobes.c
> +++ b/arch/x86/kernel/uprobes.c
[ ... ]
> @@ -719,6 +723,134 @@ static struct vm_area_struct *get_uprobe_trampoline(struct mm_struct *mm, unsign
[ ... ]
> +int uprobe_ptwrite_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
> +{
> + struct uprobes_state *old_state = &oldmm->uprobes_state;
> + struct uprobes_state *new_state = &newmm->uprobes_state;
> + struct uprobe_ptwrite_page *ptw, *new;
> + struct vm_area_struct *vma;
> + struct hlist_node *n;
> +
> + mmap_assert_write_locked(oldmm);
> + mmap_assert_write_locked(newmm);
> + hlist_for_each_entry(ptw, &old_state->head_ptwrite, node) {
> + void *src, *dst;
> +
> + /*
> + * Not using __GFP_ACCOUNT here because it triggered
> + * a deadlock.
> + */
> + new = kzalloc_obj(*new, GFP_KERNEL);
> + if (!new)
> + goto fail;
> + new->page = alloc_page(GFP_KERNEL | __GFP_ZERO);
[Severity: High]
Does stripping __GFP_ACCOUNT here allow containers to bypass memory cgroup
limits? By repeatedly forking processes with active ptwrite uprobes, a local
user could potentially consume unbounded kernel memory without being charged.
Also, since this is called under the mmap_write_lock of both the old and new
mm_structs, is it safe to use GFP_KERNEL allocations? GFP_KERNEL can enter
direct reclaim, which might attempt to reacquire the same or other locks via
page writeback or swap-out, leading to deadlocks.
[ ... ]
> @@ -1102,6 +1287,475 @@ static int copy_from_vaddr(struct mm_struct *mm, unsigned long vaddr, void *dst,
[ ... ]
> +static struct uprobe_ptwrite_page *
> +create_uprobe_ptwrite_page(struct mm_struct *mm, unsigned long vaddr)
> +{
> + struct uprobe_ptwrite_page *ptw;
> + struct vm_area_struct *vma;
> + unsigned long area;
> +
> + area = find_ptwrite_page_area(mm, vaddr);
> + if (IS_ERR_VALUE(area))
> + return NULL;
> +
> + mmap_assert_write_locked(mm);
> +
> + ptw = kzalloc_obj(*ptw, GFP_KERNEL);
> + if (!ptw)
> + return NULL;
> +
> + ptw->page = alloc_page(GFP_HIGHUSER | __GFP_ZERO);
[Severity: Medium]
Will this allocation pin an unmigratable page in a movable zone?
The GFP_HIGHUSER mask includes the __GFP_MOVABLE flag, but the returned page
is a raw page mapped via _install_special_mapping(). Since it lacks movable_ops
or LRU linkage, it is fundamentally unmigratable. This breaks the page
allocator's mobility contract and can cause permanent memory fragmentation.
[ ... ]
> +static int ptwrite_text_poke(struct arch_uprobe *auprobe,
> + struct vm_area_struct *vma, unsigned long vaddr,
> + unsigned long stub_addr)
> +{
> + u8 jmp5[5] = { 0xe9, 0, 0, 0, 0 };
> + bool first_phase_done;
> + s32 rel;
> + int err;
> +
> + if (!ptwrite_rel32(vaddr + 5, stub_addr, &rel))
> + return -ERANGE;
> + memcpy(jmp5 + 1, &rel, 4);
> +
> + err = text_poke_5byte(auprobe, vma, vaddr, jmp5,
> + auprobe->ptwrite.orig[0], false, true, true,
> + false, &first_phase_done);
> + if (err && first_phase_done) {
[Severity: High]
Can this evaluate uninitialized memory on the error path?
If text_poke_5byte() fails during its first uprobe_write() call (when setting
the INT3 breakpoint), it returns the error immediately without initializing the
first_phase_done out-parameter:
arch/x86/kernel/uprobes.c:text_poke_5byte() {
...
if (!skip_int3) {
err = uprobe_write(auprobe, vma, vaddr, &int3, 1, verify_insn,
is_register, false, &ctx);
if (err)
return err;
}
if (first_phase_done)
*first_phase_done = true;
...
}
If the uninitialized first_phase_done variable happens to be non-zero (true),
ptwrite_text_poke() will attempt a rollback by calling text_poke_5byte() again
to remove an INT3 breakpoint that was never successfully installed, which could
further fail or corrupt the instruction stream.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917230127.924985-2-ak@kernel.org?part=2
next prev parent reply other threads:[~2026-09-17 23:25 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-17 23:00 ptwrite uprobes v2 Andi Kleen
2026-09-17 23:00 ` [RFC PATCH v2 01/11] ptwrite uprobes: Add infrastructure for ptwrite uprobes Andi Kleen
2026-09-17 23:19 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 02/11] ptwrite uprobes: Add minimal low level support for x86 Andi Kleen
2026-09-17 23:25 ` sashiko-bot [this message]
2026-09-17 23:00 ` [RFC PATCH v2 03/11] ptwrite uprobes: Add a sample module to exercise interface Andi Kleen
2026-09-17 23:20 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 04/11] ptwrite uprobes: Add support to tracing infrastructure Andi Kleen
2026-09-17 23:23 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 05/11] ptwrite uprobes: Factor file-backed instruction reads Andi Kleen
2026-09-17 23:14 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 06/11] ptwrite uprobes: Add basic memory references Andi Kleen
2026-09-17 23:17 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 07/11] ptwrite uprobes: Add multinop support Andi Kleen
2026-09-17 23:22 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 08/11] ptwrite uprobes: Support instruction punning Andi Kleen
2026-09-17 23:27 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 09/11] ptwrite uprobes: Use atomic patching for multinop sites Andi Kleen
2026-09-17 23:32 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 10/11] ptwrite uprobes: Add a tutorial and overview documentation Andi Kleen
2026-09-17 23:21 ` sashiko-bot
2026-09-17 23:00 ` [RFC PATCH v2 11/11] ptwrite uprobes: Add kernel self tests Andi Kleen
2026-09-17 23:28 ` sashiko-bot
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=20260917232520.341AD1F000FF@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=ak@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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