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(size: 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(objp: vdsop); |
36 | |
37 | goto oom; |
38 | } |
39 | |
40 | copy_page(page_address(um_vdso), from: 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, addr: um_vdso_addr, PAGE_SIZE, |
65 | VM_READ|VM_EXEC| |
66 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, |
67 | pages: vdsop); |
68 | |
69 | mmap_write_unlock(mm); |
70 | |
71 | return err; |
72 | } |
73 |