linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Pu Lehui <pulehui@huaweicloud.com>
To: mhiramat@kernel.org, oleg@redhat.com, peterz@infradead.org,
	akpm@linux-foundation.org, Liam.Howlett@oracle.com,
	lorenzo.stoakes@oracle.com, vbabka@suse.cz, jannh@google.com,
	pfalcato@suse.de
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, pulehui@huawei.com
Subject: [RFC PATCH v2 1/2] mm/mremap: Fix uprobe anon page be overwritten when expanding vma during mremap
Date: Tue, 27 May 2025 13:23:50 +0000	[thread overview]
Message-ID: <20250527132351.2050820-2-pulehui@huaweicloud.com> (raw)
In-Reply-To: <20250527132351.2050820-1-pulehui@huaweicloud.com>

From: Pu Lehui <pulehui@huawei.com>

We encountered a BUG alert triggered by Syzkaller as follows:
   BUG: Bad rss-counter state mm:00000000b4a60fca type:MM_ANONPAGES val:1

And we can reproduce it with the following steps:
1. register uprobe on file at zero offset
2. mmap the file at zero offset:
   addr1 = mmap(NULL, 2 * 4096, PROT_NONE, MAP_PRIVATE, fd, 0);
3. mremap part of vma1 to new vma2:
   addr2 = mremap(addr1, 4096, 2 * 4096, MREMAP_MAYMOVE);
4. mremap back to orig addr1:
   mremap(addr2, 4096, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, addr1);

In the step 3, the vma1 range [addr1, addr1 + 4096] will be remap to new
vma2 with range [addr2, addr2 + 8192], and remap uprobe anon page from
the vma1 to vma2, then unmap the vma1 range [addr1, addr1 + 4096].
In tht step 4, the vma2 range [addr2, addr2 + 4096] will be remap back
to the addr range [addr1, addr1 + 4096]. Since the addr range [addr1 +
4096, addr1 + 8192] still maps the file, it will take
vma_merge_new_range to merge these two addr ranges, and then do
uprobe_mmap in vma_complete. Since the merged vma pgoff is also zero
offset, it will install uprobe anon page to the merged vma. However, the
upcomming move_page_tables step, which use set_pte_at to remap the vma2
uprobe anon page to the merged vma, will over map the old uprobe anon
page in the merged vma, and lead the old uprobe anon page to be orphan.

Since the uprobe anon page will be remapped to the merged vma, we can
remove the unnecessary uprobe_mmap on merged vma, that is, do not
perform uprobe_mmap on expanded vma.

This problem was first find in linux-6.6.y and also exists in the
community syzkaller:
https://lore.kernel.org/all/000000000000ada39605a5e71711@google.com/T/

The complete Syzkaller C reproduction program is as follows:

#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <syscall.h>
#include <sys/mman.h>
#include <linux/perf_event.h>

int main(int argc, char *argv[])
{
    int fd = open(FNAME, O_RDWR|O_CREAT, 0600);
    struct perf_event_attr attr = {
        .type = 9,
        .uprobe_path = (long) FNAME,
        .probe_offset = 0x0,
    };
    void *addr1, *addr2;

    write(fd, "x", 1);
    mmap(NULL, 4096, PROT_EXEC, MAP_PRIVATE, fd, 0);

    syscall(__NR_perf_event_open, &attr, 0, 0, -1, 0);
    addr1 = mmap(NULL, 2 * 4096, PROT_NONE, MAP_PRIVATE, fd, 0);
    addr2 = mremap(addr1, 4096, 2 * 4096, MREMAP_MAYMOVE);
    mremap(addr2, 4096, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, addr1);

    return 0;
}

Fixes: 78a320542e6c ("uprobes: Change valid_vma() to demand VM_MAYEXEC rather than VM_EXEC")
Signed-off-by: Pu Lehui <pulehui@huawei.com>
---
 mm/vma.c | 7 ++++++-
 mm/vma.h | 7 +++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/mm/vma.c b/mm/vma.c
index 1c6595f282e5..6445f515c7f2 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -358,7 +358,8 @@ static void vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi,
 
 	if (vp->file) {
 		i_mmap_unlock_write(vp->mapping);
-		uprobe_mmap(vp->vma);
+		if (!vp->skip_vma_uprobe)
+			uprobe_mmap(vp->vma);
 
 		if (vp->adj_next)
 			uprobe_mmap(vp->adj_next);
@@ -737,6 +738,7 @@ static int commit_merge(struct vma_merge_struct *vmg)
 	if (vma_iter_prealloc(vmg->vmi, vma))
 		return -ENOMEM;
 
+	vp.skip_vma_uprobe = vmg->skip_vma_uprobe;
 	vma_prepare(&vp);
 	/*
 	 * THP pages may need to do additional splits if we increase
@@ -1151,6 +1153,9 @@ int vma_expand(struct vma_merge_struct *vmg)
 	if (remove_next)
 		vmg->__remove_next = true;
 
+	/* skip uprobe_mmap on expanded vma */
+	vmg->skip_vma_uprobe = true;
+
 	if (commit_merge(vmg))
 		goto nomem;
 
diff --git a/mm/vma.h b/mm/vma.h
index 9a8af9be29a8..56cc0364d239 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -19,6 +19,8 @@ struct vma_prepare {
 	struct vm_area_struct *insert;
 	struct vm_area_struct *remove;
 	struct vm_area_struct *remove2;
+	/* Whether to skip uprobe_mmap on vma */
+	bool skip_vma_uprobe;
 };
 
 struct unlink_vma_file_batch {
@@ -120,6 +122,11 @@ struct vma_merge_struct {
 	 */
 	bool give_up_on_oom :1;
 
+	/*
+	 * Whether to skip uprobe_mmap on merged vma.
+	 */
+	bool skip_vma_uprobe :1;
+
 	/* Internal flags set during merge process: */
 
 	/*
-- 
2.34.1



  reply	other threads:[~2025-05-27 13:21 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-27 13:23 [RFC PATCH v2 0/2] Fix uprobe anon page be overwritten " Pu Lehui
2025-05-27 13:23 ` Pu Lehui [this message]
2025-05-27 13:34   ` [RFC PATCH v2 1/2] mm/mremap: Fix uprobe anon page be overwritten when expanding vma " Lorenzo Stoakes
2025-05-27 15:17     ` Oleg Nesterov
2025-05-27 15:27       ` Lorenzo Stoakes
2025-05-27 15:29     ` Lorenzo Stoakes
2025-05-27 16:29     ` Pu Lehui
2025-05-27 14:23   ` Oleg Nesterov
2025-05-27 16:32     ` Pu Lehui
2025-05-27 16:37       ` Lorenzo Stoakes
2025-05-27 16:52         ` Pu Lehui
2025-05-27 17:20       ` Oleg Nesterov
2025-05-29 15:09         ` Pu Lehui
2025-05-29 15:12           ` Lorenzo Stoakes
2025-05-27 15:30   ` Oleg Nesterov
2025-05-27 15:33     ` Lorenzo Stoakes
2025-05-27 15:52       ` Oleg Nesterov
2025-05-27 16:41       ` Pu Lehui
2025-05-27 16:35     ` Pu Lehui
2025-05-27 13:23 ` [RFC PATCH v2 2/2] mm/mremap: Expose abnormal new_pte during move_ptes Pu Lehui
2025-05-27 14:24   ` Oleg Nesterov

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=20250527132351.2050820-2-pulehui@huaweicloud.com \
    --to=pulehui@huaweicloud.com \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=jannh@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lorenzo.stoakes@oracle.com \
    --cc=mhiramat@kernel.org \
    --cc=oleg@redhat.com \
    --cc=peterz@infradead.org \
    --cc=pfalcato@suse.de \
    --cc=pulehui@huawei.com \
    --cc=vbabka@suse.cz \
    /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