1
0
Fork 0

x86/vsyscall: Add a new vsyscall=xonly mode

With vsyscall emulation on, a readable vsyscall page is still exposed that
contains syscall instructions that validly implement the vsyscalls.

This is required because certain dynamic binary instrumentation tools
attempt to read the call targets of call instructions in the instrumented
code.  If the instrumented code uses vsyscalls, then the vsyscall page needs
to contain readable code.

Unfortunately, leaving readable memory at a deterministic address can be
used to help various ASLR bypasses, so some hardening value can be gained
by disallowing vsyscall reads.

Given how rarely the vsyscall page needs to be readable, add a mechanism to
make the vsyscall page be execute only.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Kernel Hardening <kernel-hardening@lists.openwall.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lkml.kernel.org/r/d17655777c21bc09a7af1bbcf74e6f2b69a51152.1561610354.git.luto@kernel.org
alistair/sunxi64-5.4-dsi
Andy Lutomirski 2019-06-26 21:45:03 -07:00 committed by Thomas Gleixner
parent d974ffcfb7
commit bd49e16e33
3 changed files with 44 additions and 12 deletions

View File

@ -5100,7 +5100,12 @@
targets for exploits that can control RIP. targets for exploits that can control RIP.
emulate [default] Vsyscalls turn into traps and are emulate [default] Vsyscalls turn into traps and are
emulated reasonably safely. emulated reasonably safely. The vsyscall
page is readable.
xonly Vsyscalls turn into traps and are
emulated reasonably safely. The vsyscall
page is not readable.
none Vsyscalls don't work at all. This makes none Vsyscalls don't work at all. This makes
them quite hard to use for exploits but them quite hard to use for exploits but

View File

@ -2293,23 +2293,38 @@ choice
it can be used to assist security vulnerability exploitation. it can be used to assist security vulnerability exploitation.
This setting can be changed at boot time via the kernel command This setting can be changed at boot time via the kernel command
line parameter vsyscall=[emulate|none]. line parameter vsyscall=[emulate|xonly|none].
On a system with recent enough glibc (2.14 or newer) and no On a system with recent enough glibc (2.14 or newer) and no
static binaries, you can say None without a performance penalty static binaries, you can say None without a performance penalty
to improve security. to improve security.
If unsure, select "Emulate". If unsure, select "Emulate execution only".
config LEGACY_VSYSCALL_EMULATE config LEGACY_VSYSCALL_EMULATE
bool "Emulate" bool "Full emulation"
help help
The kernel traps and emulates calls into the fixed The kernel traps and emulates calls into the fixed vsyscall
vsyscall address mapping. This makes the mapping address mapping. This makes the mapping non-executable, but
non-executable, but it still contains known contents, it still contains readable known contents, which could be
which could be used in certain rare security vulnerability used in certain rare security vulnerability exploits. This
exploits. This configuration is recommended when userspace configuration is recommended when using legacy userspace
still uses the vsyscall area. that still uses vsyscalls along with legacy binary
instrumentation tools that require code to be readable.
An example of this type of legacy userspace is running
Pin on an old binary that still uses vsyscalls.
config LEGACY_VSYSCALL_XONLY
bool "Emulate execution only"
help
The kernel traps and emulates calls into the fixed vsyscall
address mapping and does not allow reads. This
configuration is recommended when userspace might use the
legacy vsyscall area but support for legacy binary
instrumentation of legacy code is not needed. It mitigates
certain uses of the vsyscall area as an ASLR-bypassing
buffer.
config LEGACY_VSYSCALL_NONE config LEGACY_VSYSCALL_NONE
bool "None" bool "None"

View File

@ -42,9 +42,11 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "vsyscall_trace.h" #include "vsyscall_trace.h"
static enum { EMULATE, NONE } vsyscall_mode = static enum { EMULATE, XONLY, NONE } vsyscall_mode =
#ifdef CONFIG_LEGACY_VSYSCALL_NONE #ifdef CONFIG_LEGACY_VSYSCALL_NONE
NONE; NONE;
#elif defined(CONFIG_LEGACY_VSYSCALL_XONLY)
XONLY;
#else #else
EMULATE; EMULATE;
#endif #endif
@ -54,6 +56,8 @@ static int __init vsyscall_setup(char *str)
if (str) { if (str) {
if (!strcmp("emulate", str)) if (!strcmp("emulate", str))
vsyscall_mode = EMULATE; vsyscall_mode = EMULATE;
else if (!strcmp("xonly", str))
vsyscall_mode = XONLY;
else if (!strcmp("none", str)) else if (!strcmp("none", str))
vsyscall_mode = NONE; vsyscall_mode = NONE;
else else
@ -357,12 +361,20 @@ void __init map_vsyscall(void)
extern char __vsyscall_page; extern char __vsyscall_page;
unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page); unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
if (vsyscall_mode != NONE) { /*
* For full emulation, the page needs to exist for real. In
* execute-only mode, there is no PTE at all backing the vsyscall
* page.
*/
if (vsyscall_mode == EMULATE) {
__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
PAGE_KERNEL_VVAR); PAGE_KERNEL_VVAR);
set_vsyscall_pgtable_user_bits(swapper_pg_dir); set_vsyscall_pgtable_user_bits(swapper_pg_dir);
} }
if (vsyscall_mode == XONLY)
gate_vma.vm_flags = VM_EXEC;
BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) != BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
(unsigned long)VSYSCALL_ADDR); (unsigned long)VSYSCALL_ADDR);
} }