[vz8] vdso: fix VM_BUG_ON_PAGE(PageSlab(page)) on unmap

Submitted by Andrey Ryabinin on Dec. 15, 2020, 4:19 p.m.

Details

Message ID 20201215161949.15461-1-aryabinin@virtuozzo.com
State New
Series "vdso: fix VM_BUG_ON_PAGE(PageSlab(page)) on unmap"
Headers show

Commit Message

Andrey Ryabinin Dec. 15, 2020, 4:19 p.m.
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);
 	}
 }