[amd64] Enable X86_X32 (Closes: #708070)

- Reject x32 executables if x32 ABI not supported
- Make x32 syscall support conditional on a kernel parameter
- Enable X86_X32_DISABLED so that x32 support must be explicitly enabled

svn path=/dists/sid/linux/; revision=21634
This commit is contained in:
Ben Hutchings 2014-07-27 04:08:25 +00:00
parent 805abd3343
commit a718693e7b
5 changed files with 244 additions and 1 deletions

6
debian/changelog vendored
View File

@ -4,6 +4,12 @@ linux (3.14.13-3) UNRELEASED; urgency=medium
* Update German debconf template translations (Holger Wansing) (Closes:
#756049).
[ Ben Hutchings ]
* [amd64] Reject x32 executables if x32 ABI not supported
* [amd64] Make x32 syscall support conditional on a kernel parameter
* [amd64] Enable X86_X32 (Closes: #708070) and X86_X32_DISABLED.
Use the kernel parameter "syscall.x32=y" to enable support for x32.
-- Aurelien Jarno <aurel32@debian.org> Fri, 25 Jul 2014 23:02:24 +0200
linux (3.14.13-2) unstable; urgency=medium

View File

@ -15,7 +15,8 @@ CONFIG_X86_64_ACPI_NUMA=y
CONFIG_NUMA_EMU=y
CONFIG_PCI_MMCONFIG=y
CONFIG_ISA_DMA_API=y
# CONFIG_X86_X32 is not set
CONFIG_X86_X32=y
CONFIG_X86_X32_DISABLED=y
##
## file: arch/x86/Kconfig.cpu

View File

@ -0,0 +1,31 @@
From: Ben Hutchings <ben@decadent.org.uk>
Date: Sat, 26 Jul 2014 15:03:11 +0100
Subject: x86: Reject x32 executables if x32 ABI not supported
Forwarded: http://mid.gmane.org/1406431195.29010.154.camel@deadeye.wl.decadent.org.uk
It is currently possible to execve() an x32 executable on an x86_64
kernel that has only ia32 compat enabled. However all its syscalls
will fail, even _exit(). This usually causes it to segfault.
Change the ELF compat architecture check so that x32 executables are
rejected if we don't support the x32 ABI.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
arch/x86/include/asm/elf.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -155,8 +155,9 @@ do { \
#define elf_check_arch(x) \
((x)->e_machine == EM_X86_64)
-#define compat_elf_check_arch(x) \
- (elf_check_arch_ia32(x) || (x)->e_machine == EM_X86_64)
+#define compat_elf_check_arch(x) \
+ (elf_check_arch_ia32(x) || \
+ (IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
#if __USER32_DS != __USER_DS
# error "The following code assumes __USER32_DS == __USER_DS"

View File

@ -0,0 +1,203 @@
From: Ben Hutchings <ben@decadent.org.uk>
Date: Fri, 25 Jul 2014 01:16:15 +0100
Subject: x86: Make x32 syscall support conditional on a kernel parameter
Bug-Debian: https://bugs.debian.org/708070
Enabling x32 in the standard amd64 kernel would increase its attack
surface while provide no benefit to the vast majority of its users.
No-one seems interested in regularly checking for vulnerabilities
specific to x32 (at least no-one with a white hat).
Still, adding another flavour just to turn on x32 seems wasteful. And
the only difference on syscall entry is whether we mask the x32 flag
out of the syscall number before range-checking it.
So replace the mask (andl) instruction with a nop and add a kernel
parameter "syscall.x32" which allows it to be enabled/disabled at
boot time. Add a Kconfig parameter to set the default.
Change the comparison instruction to cmpq, because now the upper 32
bits may or may not be cleared by the previous instruction.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
Documentation/kernel-parameters.txt | 4 ++++
arch/x86/Kconfig | 8 +++++++
arch/x86/include/asm/elf.h | 8 ++++++-
arch/x86/kernel/entry_64.S | 36 ++++++++++++++++++++++---------
arch/x86/kernel/syscall_64.c | 43 +++++++++++++++++++++++++++++++++++++
5 files changed, 88 insertions(+), 11 deletions(-)
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3132,6 +3132,10 @@ bytes respectively. Such letter suffixes
switches= [HW,M68k]
+ syscall.x32= [KNL,x86_64] Enable/disable use of x32 syscalls on
+ an x86_64 kernel where CONFIG_X86_X32 is enabled.
+ Default depends on CONFIG_X86_X32_DISABLED.
+
sysfs.deprecated=0|1 [KNL]
Enable/disable old style sysfs layout for old udev
on older distributions. When this option is enabled
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2383,6 +2383,14 @@ config X86_X32
elf32_x86_64 support enabled to compile a kernel with this
option set.
+config X86_X32_DISABLED
+ bool "x32 ABI disabled by default"
+ depends on X86_X32
+ default n
+ help
+ Disable the x32 ABI unless explicitly enabled using the
+ kernel paramter "syscall.x32=y".
+
config COMPAT
def_bool y
depends on IA32_EMULATION || X86_X32
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -149,6 +149,12 @@ do { \
#else /* CONFIG_X86_32 */
+#ifdef CONFIG_X86_X32_ABI
+extern bool x32_enabled;
+#else
+#define x32_enabled 0
+#endif
+
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
@@ -157,7 +163,7 @@ do { \
#define compat_elf_check_arch(x) \
(elf_check_arch_ia32(x) || \
- (IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
+ (x32_enabled && (x)->e_machine == EM_X86_64))
#if __USER32_DS != __USER_DS
# error "The following code assumes __USER32_DS == __USER_DS"
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -618,12 +618,14 @@ GLOBAL(system_call_after_swapgs)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
jnz tracesys
system_call_fastpath:
-#if __SYSCALL_MASK == ~0
- cmpq $__NR_syscall_max,%rax
-#else
- andl $__SYSCALL_MASK,%eax
- cmpl $__NR_syscall_max,%eax
+#if __SYSCALL_MASK != ~0
+ .globl system_call_fast_maybe_mask
+ .globl system_call_fast_masked
+system_call_fast_maybe_mask:
+ .byte P6_NOP5_ATOMIC
+system_call_fast_masked:
#endif
+ cmpq $__NR_syscall_max,%rax
ja badsys
movq %r10,%rcx
call *sys_call_table(,%rax,8) # XXX: rip relative
@@ -737,12 +739,14 @@ tracesys:
*/
LOAD_ARGS ARGOFFSET, 1
RESTORE_REST
-#if __SYSCALL_MASK == ~0
- cmpq $__NR_syscall_max,%rax
-#else
- andl $__SYSCALL_MASK,%eax
- cmpl $__NR_syscall_max,%eax
+#if __SYSCALL_MASK != ~0
+ .globl system_call_trace_maybe_mask
+ .globl system_call_trace_masked
+system_call_trace_maybe_mask:
+ .byte P6_NOP5_ATOMIC
+system_call_trace_masked:
#endif
+ cmpq $__NR_syscall_max,%rax
ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */
movq %r10,%rcx /* fixup for C */
call *sys_call_table(,%rax,8)
@@ -813,6 +817,18 @@ int_restore_rest:
CFI_ENDPROC
END(system_call)
+#if __SYSCALL_MASK != ~0
+ /*
+ * This replaces the nops before the syscall range check
+ * if syscall.x32 is set
+ */
+ .globl system_call_mask
+ .globl system_call_mask_end
+system_call_mask:
+ andl $__SYSCALL_MASK,%eax
+system_call_mask_end:
+#endif
+
.macro FORK_LIKE func
ENTRY(stub_\func)
CFI_STARTPROC
--- a/arch/x86/kernel/syscall_64.c
+++ b/arch/x86/kernel/syscall_64.c
@@ -3,8 +3,14 @@
#include <linux/linkage.h>
#include <linux/sys.h>
#include <linux/cache.h>
+#include <linux/moduleparam.h>
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "syscall."
+#include <linux/bug.h>
+#include <linux/init.h>
#include <asm/asm-offsets.h>
#include <asm/syscall.h>
+#include <asm/alternative.h>
#define __SYSCALL_COMMON(nr, sym, compat) __SYSCALL_64(nr, sym, compat)
@@ -30,3 +36,40 @@ asmlinkage const sys_call_ptr_t sys_call
[0 ... __NR_syscall_max] = &sys_ni_syscall,
#include <asm/syscalls_64.h>
};
+
+#ifdef CONFIG_X86_X32_ABI
+
+/* Maybe enable x32 syscalls */
+
+bool x32_enabled = !IS_ENABLED(CONFIG_X86_X32_DISABLED);
+module_param_named(x32, x32_enabled, bool, 0444);
+
+extern char system_call_fast_masked[], system_call_fast_maybe_mask[],
+ system_call_trace_masked[], system_call_trace_maybe_mask[],
+ system_call_mask_end[], system_call_mask[];
+
+static int __init x32_enable(void)
+{
+ BUG_ON(system_call_fast_masked - system_call_fast_maybe_mask != 5);
+ BUG_ON(system_call_trace_masked - system_call_trace_maybe_mask != 5);
+ BUG_ON(system_call_mask_end - system_call_mask != 5);
+
+ if (x32_enabled) {
+ text_poke_early(system_call_fast_maybe_mask,
+ system_call_mask, 5);
+ text_poke_early(system_call_trace_maybe_mask,
+ system_call_mask, 5);
+#ifdef CONFIG_X86_X32_DISABLED
+ pr_info("Enabled x32 syscalls\n");
+#endif
+ }
+#ifndef CONFIG_X86_X32_DISABLED
+ else
+ pr_info("Disabled x32 syscalls\n");
+#endif
+
+ return 0;
+}
+late_initcall(x32_enable);
+
+#endif

View File

@ -110,3 +110,5 @@ features/mips/MIPS-Malta-Let-PIIX4-respond-to-PCI-special-cycles.patch
features/mips/MIPS-Malta-hang-on-halt.patch
features/mips/MIPS-Malta-support-powering-down.patch
features/mips/MIPS-Loongson-3-Add-Loongson-LS3A-RS780E-1-way-machi.patch
bugfix/x86/x86-reject-x32-executables-if-x32-abi-not-supported.patch
features/x86/x86-make-x32-syscall-support-conditional.patch