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 int err; 56 struct mm_struct *mm = current->mm; 57 58 if (!vdso_enabled) 59 return 0; 60 61 if (mmap_write_lock_killable(mm)) 62 return -EINTR; 63 64 err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE, 65 VM_READ|VM_EXEC| 66 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 67 vdsop); 68 69 mmap_write_unlock(mm); 70 71 return err; 72 } 73