1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * arch/sh/kernel/vsyscall/vsyscall.c
4 *
5 * Copyright (C) 2006 Paul Mundt
6 *
7 * vDSO randomization
8 * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
9 */
10 #include <linux/mm.h>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/gfp.h>
14 #include <linux/module.h>
15 #include <linux/elf.h>
16 #include <linux/sched.h>
17 #include <linux/sysctl.h>
18 #include <linux/err.h>
19
20 /*
21 * Should the kernel map a VDSO page into processes and pass its
22 * address down to glibc upon exec()?
23 */
24 unsigned int __read_mostly vdso_enabled = 1;
25 EXPORT_SYMBOL_GPL(vdso_enabled);
26
vdso_setup(char * s)27 static int __init vdso_setup(char *s)
28 {
29 vdso_enabled = simple_strtoul(s, NULL, 0);
30 return 1;
31 }
32 __setup("vdso=", vdso_setup);
33
34 static const struct ctl_table vdso_table[] = {
35 {
36 .procname = "vdso_enabled",
37 .data = &vdso_enabled,
38 .maxlen = sizeof(vdso_enabled),
39 .mode = 0644,
40 .proc_handler = proc_dointvec_minmax,
41 .extra1 = SYSCTL_ZERO,
42 .extra2 = SYSCTL_ONE,
43 },
44 };
45
46 /*
47 * These symbols are defined by vsyscall.o to mark the bounds
48 * of the ELF DSO images included therein.
49 */
50 extern const char vsyscall_trapa_start, vsyscall_trapa_end;
51 static struct page *syscall_pages[1];
52 static struct vm_special_mapping vdso_mapping = {
53 .name = "[vdso]",
54 .pages = syscall_pages,
55 };
56
vsyscall_init(void)57 int __init vsyscall_init(void)
58 {
59 void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
60 syscall_pages[0] = virt_to_page(syscall_page);
61
62 /*
63 * XXX: Map this page to a fixmap entry if we get around
64 * to adding the page to ELF core dumps
65 */
66
67 memcpy(syscall_page,
68 &vsyscall_trapa_start,
69 &vsyscall_trapa_end - &vsyscall_trapa_start);
70
71 return 0;
72 }
73
vm_sysctl_init(void)74 static int __init vm_sysctl_init(void)
75 {
76 register_sysctl_init("vm", vdso_table);
77 return 0;
78 }
79
80 fs_initcall(vm_sysctl_init);
81
82 /* Setup a VMA at program startup for the vsyscall page */
arch_setup_additional_pages(struct linux_binprm * bprm,int uses_interp)83 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
84 {
85 struct mm_struct *mm = current->mm;
86 struct vm_area_struct *vma;
87 unsigned long addr;
88 int ret;
89
90 if (mmap_write_lock_killable(mm))
91 return -EINTR;
92
93 addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
94 if (IS_ERR_VALUE(addr)) {
95 ret = addr;
96 goto up_fail;
97 }
98
99 vdso_mapping.pages = syscall_pages;
100 vma = _install_special_mapping(mm, addr, PAGE_SIZE,
101 VM_READ | VM_EXEC |
102 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
103 &vdso_mapping);
104 ret = PTR_ERR(vma);
105 if (IS_ERR(vma))
106 goto up_fail;
107
108 current->mm->context.vdso = (void *)addr;
109 ret = 0;
110
111 up_fail:
112 mmap_write_unlock(mm);
113 return ret;
114 }
115
arch_vma_name(struct vm_area_struct * vma)116 const char *arch_vma_name(struct vm_area_struct *vma)
117 {
118 if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
119 return "[vdso]";
120
121 return NULL;
122 }
123