Skip to content

Commit 7fdd034

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 402d84ad9e89bd4cbfd07ca8598532b7021daf95) Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent f940773 commit 7fdd034

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
@@ -1213,6 +1213,12 @@ static void privcmd_close(struct vm_area_struct *vma)
12131213
kvfree(pages);
12141214
}
12151215

1216+
static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr)
1217+
{
1218+
/* Forbid splitting, avoids double free via privcmd_close(). */
1219+
return -EINVAL;
1220+
}
1221+
12161222
static vm_fault_t privcmd_fault(struct vm_fault *vmf)
12171223
{
12181224
printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
@@ -1224,6 +1230,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf)
12241230

12251231
static const struct vm_operations_struct privcmd_vm_ops = {
12261232
.close = privcmd_close,
1233+
.may_split = privcmd_may_split,
12271234
.fault = privcmd_fault
12281235
};
12291236

0 commit comments

Comments
 (0)