Skip to content

Commit f76d649

Browse files
jgross1opsiff
authored andcommitted
xen/privcmd: fix double free via VMA splitting
commit 24daca4fc07f3ff8cd0e3f629cd982187f48436a upstream. privcmd_vm_ops defines .close (privcmd_close), but neither .may_split nor .open. When userspace does a partial munmap() on a privcmd mapping, the kernel splits the VMA via __split_vma(). Since may_split is NULL, the split is allowed. vm_area_dup() copies vm_private_data (a pages array allocated in alloc_empty_pages()) into the new VMA without any fixup, because there is no .open callback. Both VMAs now point to the same pages array. When the unmapped portion is closed, privcmd_close() calls: - xen_unmap_domain_gfn_range() - xen_free_unpopulated_pages() - kvfree(pages) The surviving VMA still holds the dangling pointer. When it is later destroyed, the same sequence runs again, which leads to a double free. Fix this issue by adding a .may_split callback denying the VMA split. This is XSA-487 / CVE-2026-31787 Fixes: d71f513 ("xen: privcmd: support autotranslated physmap guests.") Reported-by: Atharva Vartak <atharva.a.vartak@gmail.com> Suggested-by: Atharva Vartak <atharva.a.vartak@gmail.com> Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit 446ee446d9ae66f36e95c3c90bbcc4e56b94cde0) Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent 5c8758e commit f76d649

1 file changed

Lines changed: 7 additions & 0 deletions

File tree

drivers/xen/privcmd.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,12 @@ static void privcmd_close(struct vm_area_struct *vma)
16191619
kvfree(pages);
16201620
}
16211621

1622+
static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr)
1623+
{
1624+
/* Forbid splitting, avoids double free via privcmd_close(). */
1625+
return -EINVAL;
1626+
}
1627+
16221628
static vm_fault_t privcmd_fault(struct vm_fault *vmf)
16231629
{
16241630
printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
@@ -1630,6 +1636,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf)
16301636

16311637
static const struct vm_operations_struct privcmd_vm_ops = {
16321638
.close = privcmd_close,
1639+
.may_split = privcmd_may_split,
16331640
.fault = privcmd_fault
16341641
};
16351642

0 commit comments

Comments
 (0)