xref: /openbmc/linux/arch/x86/entry/vsyscall/vsyscall_64.c (revision eb3fcf007fffe5830d815e713591f3e858f2a365)
1 /*
2  * Copyright (c) 2012-2014 Andy Lutomirski <luto@amacapital.net>
3  *
4  * Based on the original implementation which is:
5  *  Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
6  *  Copyright 2003 Andi Kleen, SuSE Labs.
7  *
8  *  Parts of the original code have been moved to arch/x86/vdso/vma.c
9  *
10  * This file implements vsyscall emulation.  vsyscalls are a legacy ABI:
11  * Userspace can request certain kernel services by calling fixed
12  * addresses.  This concept is problematic:
13  *
14  * - It interferes with ASLR.
15  * - It's awkward to write code that lives in kernel addresses but is
16  *   callable by userspace at fixed addresses.
17  * - The whole concept is impossible for 32-bit compat userspace.
18  * - UML cannot easily virtualize a vsyscall.
19  *
20  * As of mid-2014, I believe that there is no new userspace code that
21  * will use a vsyscall if the vDSO is present.  I hope that there will
22  * soon be no new userspace code that will ever use a vsyscall.
23  *
24  * The code in this file emulates vsyscalls when notified of a page
25  * fault to a vsyscall address.
26  */
27 
28 #include <linux/kernel.h>
29 #include <linux/timer.h>
30 #include <linux/syscalls.h>
31 #include <linux/ratelimit.h>
32 
33 #include <asm/vsyscall.h>
34 #include <asm/unistd.h>
35 #include <asm/fixmap.h>
36 #include <asm/traps.h>
37 
38 #define CREATE_TRACE_POINTS
39 #include "vsyscall_trace.h"
40 
41 static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
42 
43 static int __init vsyscall_setup(char *str)
44 {
45 	if (str) {
46 		if (!strcmp("emulate", str))
47 			vsyscall_mode = EMULATE;
48 		else if (!strcmp("native", str))
49 			vsyscall_mode = NATIVE;
50 		else if (!strcmp("none", str))
51 			vsyscall_mode = NONE;
52 		else
53 			return -EINVAL;
54 
55 		return 0;
56 	}
57 
58 	return -EINVAL;
59 }
60 early_param("vsyscall", vsyscall_setup);
61 
62 static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
63 			      const char *message)
64 {
65 	if (!show_unhandled_signals)
66 		return;
67 
68 	printk_ratelimited("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
69 			   level, current->comm, task_pid_nr(current),
70 			   message, regs->ip, regs->cs,
71 			   regs->sp, regs->ax, regs->si, regs->di);
72 }
73 
74 static int addr_to_vsyscall_nr(unsigned long addr)
75 {
76 	int nr;
77 
78 	if ((addr & ~0xC00UL) != VSYSCALL_ADDR)
79 		return -EINVAL;
80 
81 	nr = (addr & 0xC00UL) >> 10;
82 	if (nr >= 3)
83 		return -EINVAL;
84 
85 	return nr;
86 }
87 
88 static bool write_ok_or_segv(unsigned long ptr, size_t size)
89 {
90 	/*
91 	 * XXX: if access_ok, get_user, and put_user handled
92 	 * sig_on_uaccess_error, this could go away.
93 	 */
94 
95 	if (!access_ok(VERIFY_WRITE, (void __user *)ptr, size)) {
96 		siginfo_t info;
97 		struct thread_struct *thread = &current->thread;
98 
99 		thread->error_code	= 6;  /* user fault, no page, write */
100 		thread->cr2		= ptr;
101 		thread->trap_nr		= X86_TRAP_PF;
102 
103 		memset(&info, 0, sizeof(info));
104 		info.si_signo		= SIGSEGV;
105 		info.si_errno		= 0;
106 		info.si_code		= SEGV_MAPERR;
107 		info.si_addr		= (void __user *)ptr;
108 
109 		force_sig_info(SIGSEGV, &info, current);
110 		return false;
111 	} else {
112 		return true;
113 	}
114 }
115 
116 bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
117 {
118 	struct task_struct *tsk;
119 	unsigned long caller;
120 	int vsyscall_nr, syscall_nr, tmp;
121 	int prev_sig_on_uaccess_error;
122 	long ret;
123 
124 	/*
125 	 * No point in checking CS -- the only way to get here is a user mode
126 	 * trap to a high address, which means that we're in 64-bit user code.
127 	 */
128 
129 	WARN_ON_ONCE(address != regs->ip);
130 
131 	if (vsyscall_mode == NONE) {
132 		warn_bad_vsyscall(KERN_INFO, regs,
133 				  "vsyscall attempted with vsyscall=none");
134 		return false;
135 	}
136 
137 	vsyscall_nr = addr_to_vsyscall_nr(address);
138 
139 	trace_emulate_vsyscall(vsyscall_nr);
140 
141 	if (vsyscall_nr < 0) {
142 		warn_bad_vsyscall(KERN_WARNING, regs,
143 				  "misaligned vsyscall (exploit attempt or buggy program) -- look up the vsyscall kernel parameter if you need a workaround");
144 		goto sigsegv;
145 	}
146 
147 	if (get_user(caller, (unsigned long __user *)regs->sp) != 0) {
148 		warn_bad_vsyscall(KERN_WARNING, regs,
149 				  "vsyscall with bad stack (exploit attempt?)");
150 		goto sigsegv;
151 	}
152 
153 	tsk = current;
154 
155 	/*
156 	 * Check for access_ok violations and find the syscall nr.
157 	 *
158 	 * NULL is a valid user pointer (in the access_ok sense) on 32-bit and
159 	 * 64-bit, so we don't need to special-case it here.  For all the
160 	 * vsyscalls, NULL means "don't write anything" not "write it at
161 	 * address 0".
162 	 */
163 	switch (vsyscall_nr) {
164 	case 0:
165 		if (!write_ok_or_segv(regs->di, sizeof(struct timeval)) ||
166 		    !write_ok_or_segv(regs->si, sizeof(struct timezone))) {
167 			ret = -EFAULT;
168 			goto check_fault;
169 		}
170 
171 		syscall_nr = __NR_gettimeofday;
172 		break;
173 
174 	case 1:
175 		if (!write_ok_or_segv(regs->di, sizeof(time_t))) {
176 			ret = -EFAULT;
177 			goto check_fault;
178 		}
179 
180 		syscall_nr = __NR_time;
181 		break;
182 
183 	case 2:
184 		if (!write_ok_or_segv(regs->di, sizeof(unsigned)) ||
185 		    !write_ok_or_segv(regs->si, sizeof(unsigned))) {
186 			ret = -EFAULT;
187 			goto check_fault;
188 		}
189 
190 		syscall_nr = __NR_getcpu;
191 		break;
192 	}
193 
194 	/*
195 	 * Handle seccomp.  regs->ip must be the original value.
196 	 * See seccomp_send_sigsys and Documentation/prctl/seccomp_filter.txt.
197 	 *
198 	 * We could optimize the seccomp disabled case, but performance
199 	 * here doesn't matter.
200 	 */
201 	regs->orig_ax = syscall_nr;
202 	regs->ax = -ENOSYS;
203 	tmp = secure_computing();
204 	if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
205 		warn_bad_vsyscall(KERN_DEBUG, regs,
206 				  "seccomp tried to change syscall nr or ip");
207 		do_exit(SIGSYS);
208 	}
209 	regs->orig_ax = -1;
210 	if (tmp)
211 		goto do_ret;  /* skip requested */
212 
213 	/*
214 	 * With a real vsyscall, page faults cause SIGSEGV.  We want to
215 	 * preserve that behavior to make writing exploits harder.
216 	 */
217 	prev_sig_on_uaccess_error = current_thread_info()->sig_on_uaccess_error;
218 	current_thread_info()->sig_on_uaccess_error = 1;
219 
220 	ret = -EFAULT;
221 	switch (vsyscall_nr) {
222 	case 0:
223 		ret = sys_gettimeofday(
224 			(struct timeval __user *)regs->di,
225 			(struct timezone __user *)regs->si);
226 		break;
227 
228 	case 1:
229 		ret = sys_time((time_t __user *)regs->di);
230 		break;
231 
232 	case 2:
233 		ret = sys_getcpu((unsigned __user *)regs->di,
234 				 (unsigned __user *)regs->si,
235 				 NULL);
236 		break;
237 	}
238 
239 	current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error;
240 
241 check_fault:
242 	if (ret == -EFAULT) {
243 		/* Bad news -- userspace fed a bad pointer to a vsyscall. */
244 		warn_bad_vsyscall(KERN_INFO, regs,
245 				  "vsyscall fault (exploit attempt?)");
246 
247 		/*
248 		 * If we failed to generate a signal for any reason,
249 		 * generate one here.  (This should be impossible.)
250 		 */
251 		if (WARN_ON_ONCE(!sigismember(&tsk->pending.signal, SIGBUS) &&
252 				 !sigismember(&tsk->pending.signal, SIGSEGV)))
253 			goto sigsegv;
254 
255 		return true;  /* Don't emulate the ret. */
256 	}
257 
258 	regs->ax = ret;
259 
260 do_ret:
261 	/* Emulate a ret instruction. */
262 	regs->ip = caller;
263 	regs->sp += 8;
264 	return true;
265 
266 sigsegv:
267 	force_sig(SIGSEGV, current);
268 	return true;
269 }
270 
271 /*
272  * A pseudo VMA to allow ptrace access for the vsyscall page.  This only
273  * covers the 64bit vsyscall page now. 32bit has a real VMA now and does
274  * not need special handling anymore:
275  */
276 static const char *gate_vma_name(struct vm_area_struct *vma)
277 {
278 	return "[vsyscall]";
279 }
280 static const struct vm_operations_struct gate_vma_ops = {
281 	.name = gate_vma_name,
282 };
283 static struct vm_area_struct gate_vma = {
284 	.vm_start	= VSYSCALL_ADDR,
285 	.vm_end		= VSYSCALL_ADDR + PAGE_SIZE,
286 	.vm_page_prot	= PAGE_READONLY_EXEC,
287 	.vm_flags	= VM_READ | VM_EXEC,
288 	.vm_ops		= &gate_vma_ops,
289 };
290 
291 struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
292 {
293 #ifdef CONFIG_COMPAT
294 	if (!mm || mm->context.ia32_compat)
295 		return NULL;
296 #endif
297 	if (vsyscall_mode == NONE)
298 		return NULL;
299 	return &gate_vma;
300 }
301 
302 int in_gate_area(struct mm_struct *mm, unsigned long addr)
303 {
304 	struct vm_area_struct *vma = get_gate_vma(mm);
305 
306 	if (!vma)
307 		return 0;
308 
309 	return (addr >= vma->vm_start) && (addr < vma->vm_end);
310 }
311 
312 /*
313  * Use this when you have no reliable mm, typically from interrupt
314  * context. It is less reliable than using a task's mm and may give
315  * false positives.
316  */
317 int in_gate_area_no_mm(unsigned long addr)
318 {
319 	return vsyscall_mode != NONE && (addr & PAGE_MASK) == VSYSCALL_ADDR;
320 }
321 
322 void __init map_vsyscall(void)
323 {
324 	extern char __vsyscall_page;
325 	unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
326 
327 	if (vsyscall_mode != NONE)
328 		__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
329 			     vsyscall_mode == NATIVE
330 			     ? PAGE_KERNEL_VSYSCALL
331 			     : PAGE_KERNEL_VVAR);
332 
333 	BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
334 		     (unsigned long)VSYSCALL_ADDR);
335 }
336