1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> 4 */ 5 6 #include <linux/slab.h> 7 #include <linux/sched.h> 8 #include <linux/mm.h> 9 #include <asm/page.h> 10 #include <asm/elf.h> 11 #include <linux/init.h> 12 13 static unsigned int __read_mostly vdso_enabled = 1; 14 unsigned long um_vdso_addr; 15 16 extern unsigned long task_size; 17 extern char vdso_start[], vdso_end[]; 18 19 static struct page **vdsop; 20 21 static int __init init_vdso(void) 22 { 23 struct page *um_vdso; 24 25 BUG_ON(vdso_end - vdso_start > PAGE_SIZE); 26 27 um_vdso_addr = task_size - PAGE_SIZE; 28 29 vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL); 30 if (!vdsop) 31 goto oom; 32 33 um_vdso = alloc_page(GFP_KERNEL); 34 if (!um_vdso) { 35 kfree(vdsop); 36 37 goto oom; 38 } 39 40 copy_page(page_address(um_vdso), vdso_start); 41 *vdsop = um_vdso; 42 43 return 0; 44 45 oom: 46 printk(KERN_ERR "Cannot allocate vdso\n"); 47 vdso_enabled = 0; 48 49 return -ENOMEM; 50 } 51 subsys_initcall(init_vdso); 52 53 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 54 { 55 struct vm_area_struct *vma; 56 struct mm_struct *mm = current->mm; 57 static struct vm_special_mapping vdso_mapping = { 58 .name = "[vdso]", 59 }; 60 61 if (!vdso_enabled) 62 return 0; 63 64 if (mmap_write_lock_killable(mm)) 65 return -EINTR; 66 67 vdso_mapping.pages = vdsop; 68 vma = _install_special_mapping(mm, um_vdso_addr, PAGE_SIZE, 69 VM_READ|VM_EXEC| 70 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 71 &vdso_mapping); 72 73 mmap_write_unlock(mm); 74 75 return IS_ERR(vma) ? PTR_ERR(vma) : 0; 76 } 77