[RHEL8,COMMIT] vdso: fix VM_BUG_ON_PAGE(PageSlab(page)) on unmap

Submitted by Konstantin Khorenko on Dec. 15, 2020, 5:12 p.m.

Details

Message ID 202012151712.0BFHCId04029377@finist-co8.sw.ru
State New
Series "vdso: fix VM_BUG_ON_PAGE(PageSlab(page)) on unmap"
Headers show

Commit Message

Konstantin Khorenko Dec. 15, 2020, 5:12 p.m.
The commit is pushed to "branch-rh8-4.18.0-240.1.1.vz8.5.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-240.1.1.vz8.5.1
------>
commit eac26b43815a2f0ebc2128f9161097bed17bdc71
Author: Andrey Ryabinin <aryabinin@virtuozzo.com>
Date:   Tue Dec 15 20:12:18 2020 +0300

    vdso: fix VM_BUG_ON_PAGE(PageSlab(page)) on unmap
    
    vdso_data is mapped to userspace which means that we can't
    use kmalloc() to allocate it. Kmalloc() doesn't even guarantee
    that we will get page aligned memory.
    
     kernel BUG at include/linux/mm.h:693!
     RIP: 0010:unmap_page_range+0x15f2/0x2630
     Call Trace:
      unmap_vmas+0x11e/0x1d0
      exit_mmap+0x215/0x420
      mmput+0x10a/0x400
      do_exit+0x98f/0x2d00
      do_group_exit+0xec/0x2b0
      __x64_sys_exit_group+0x3a/0x50
      do_syscall_64+0xa5/0x4d0
      entry_SYSCALL_64_after_hwframe+0x6a/0xdf
    
    Use alloc_pages_exact() to allocate it. We can't use
    alloc_pages(), or __get_free_pages() here since vdso_fault()
    need to perform get_page() on individual sub-pages and alloc_pages()
    doesn't initalize sub-pages.
    
    https://jira.sw.ru/browse/PSBM-123551
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 kernel/ve/ve.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index b114e2918bb7..0c6630c6616a 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -568,7 +568,7 @@  static int copy_vdso(struct vdso_image **vdso_dst, const struct vdso_image *vdso
 	if (!vdso)
 		return -ENOMEM;
 
-	vdso_data = kmalloc(vdso_src->size, GFP_KERNEL);
+	vdso_data = alloc_pages_exact(vdso_src->size, GFP_KERNEL);
 	if (!vdso_data) {
 		kfree(vdso);
 		return -ENOMEM;
@@ -585,11 +585,11 @@  static int copy_vdso(struct vdso_image **vdso_dst, const struct vdso_image *vdso
 static void ve_free_vdso(struct ve_struct *ve)
 {
 	if (ve->vdso_64 && ve->vdso_64 != &vdso_image_64) {
-		kfree(ve->vdso_64->data);
+		free_pages_exact(ve->vdso_64->data, ve->vdso_64->size);
 		kfree(ve->vdso_64);
 	}
 	if (ve->vdso_32 && ve->vdso_32 != &vdso_image_32) {
-		kfree(ve->vdso_32->data);
+		free_pages_exact(ve->vdso_32->data, ve->vdso_32->size);
 		kfree(ve->vdso_32);
 	}
 }