[PATCH] mm: avoid orphaned uprobe
From: Lorenzo Stoakes
Date: Tue May 27 2025 - 09:11:26 EST
If, on mremap, me move a file-backed VMA mapped at offset 0 that possess a
uprobe and it merges with an adjacent VMA, we will then invoke
uprobe_mmap() once again to install a uprobe into this newly established
VMA.
This is problematic, as when we then move the page tables back into place,
we overwrite the uprobe entry and thus orphan the merge-established uprobe.
Avoid this by threading state to explicitly disallow the establishment of a
new uprobe upon merge under these circumstances.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx>
---
mm/vma.c | 21 ++++++++++++++++++---
mm/vma.h | 5 +++++
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/mm/vma.c b/mm/vma.c
index 1c6595f282e5..cc18d1dcdc57 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -169,6 +169,9 @@ static void init_multi_vma_prep(struct vma_prepare *vp,
vp->file = vma->vm_file;
if (vp->file)
vp->mapping = vma->vm_file->f_mapping;
+
+ if (vmg && vmg->no_uprobe)
+ vp->no_uprobe = true;
}
/*
@@ -358,10 +361,13 @@ 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->adj_next)
- uprobe_mmap(vp->adj_next);
+ if (!vp->no_uprobe) {
+ uprobe_mmap(vp->vma);
+
+ if (vp->adj_next)
+ uprobe_mmap(vp->adj_next);
+ }
}
if (vp->remove) {
@@ -1830,6 +1836,15 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
vmg.middle = NULL; /* New VMA range. */
vmg.pgoff = pgoff;
vmg.next = vma_iter_next_rewind(&vmi, NULL);
+
+ /*
+ * If the VMA we are copying might contain a uprobe PTE, ensure that we
+ * do not establish one upon merge. otherwise, when mremap() moves page
+ * tables into place, we'll orphan the one just created.
+ */
+ if (vma->vm_file && vma->vm_pgoff == 0)
+ vmg.no_uprobe = true;
+
new_vma = vma_merge_new_range(&vmg);
if (new_vma) {
diff --git a/mm/vma.h b/mm/vma.h
index 9a8af9be29a8..4c35c5ab1aa2 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;
+
+ bool no_uprobe :1;
};
struct unlink_vma_file_batch {
@@ -120,6 +122,9 @@ struct vma_merge_struct {
*/
bool give_up_on_oom :1;
+ /* If set, do not install a uprobe upon merge. */
+ bool no_uprobe :1;
+
/* Internal flags set during merge process: */
/*
--
2.49.0