Skip to content

Commit 24daca4

Browse files
committed
xen/privcmd: fix double free via VMA splitting
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>
1 parent 27fdbab commit 24daca4

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
@@ -1620,6 +1620,12 @@ static void privcmd_close(struct vm_area_struct *vma)
16201620
kvfree(pages);
16211621
}
16221622

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

16321638
static const struct vm_operations_struct privcmd_vm_ops = {
16331639
.close = privcmd_close,
1640+
.may_split = privcmd_may_split,
16341641
.fault = privcmd_fault
16351642
};
16361643

0 commit comments

Comments
 (0)