diff options
Diffstat (limited to 'debian/patches/features/x86/x86-make-x32-syscall-support-conditional.patch')
-rw-r--r-- | debian/patches/features/x86/x86-make-x32-syscall-support-conditional.patch | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/debian/patches/features/x86/x86-make-x32-syscall-support-conditional.patch b/debian/patches/features/x86/x86-make-x32-syscall-support-conditional.patch new file mode 100644 index 000000000..3dde15cce --- /dev/null +++ b/debian/patches/features/x86/x86-make-x32-syscall-support-conditional.patch @@ -0,0 +1,227 @@ +From: Ben Hutchings <ben@decadent.org.uk> +Date: Mon, 12 Feb 2018 23:59:26 +0000 +Subject: x86: Make x32 syscall support conditional on a kernel parameter +Bug-Debian: https://bugs.debian.org/708070 +Forwarded: https://lore.kernel.org/lkml/1415245982.3398.53.camel@decadent.org.uk/T/#u + +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 differences on syscall entry are a few instructions that mask +out the x32 flag and compare the syscall number. + +Use a static key to control whether x32 syscalls are really enabled, a +Kconfig parameter to set its default value and a kernel parameter +"syscall.x32" to change it at boot time. + +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + Documentation/admin-guide/kernel-parameters.txt | 4 ++ + arch/x86/Kconfig | 8 ++++ + arch/x86/entry/common.c | 11 +++++- + arch/x86/entry/syscall_64.c | 41 ++++++++++++++++++++++++ + arch/x86/include/asm/elf.h | 4 +- + arch/x86/include/asm/syscall.h | 13 +++++++ + arch/x86/include/asm/unistd.h | 4 +- + 7 files changed, 80 insertions(+), 5 deletions(-) + +Index: linux/Documentation/admin-guide/kernel-parameters.txt +=================================================================== +--- linux.orig/Documentation/admin-guide/kernel-parameters.txt ++++ linux/Documentation/admin-guide/kernel-parameters.txt +@@ -4501,6 +4501,10 @@ + + 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 +Index: linux/arch/x86/Kconfig +=================================================================== +--- linux.orig/arch/x86/Kconfig ++++ linux/arch/x86/Kconfig +@@ -2884,6 +2884,14 @@ config COMPAT_32 + select HAVE_UID16 + select OLD_SIGSUSPEND3 + ++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 +Index: linux/arch/x86/entry/common.c +=================================================================== +--- linux.orig/arch/x86/entry/common.c ++++ linux/arch/x86/entry/common.c +@@ -287,12 +287,21 @@ __visible void do_syscall_64(unsigned lo + * table. The only functional difference is the x32 bit in + * regs->orig_ax, which changes the behavior of some syscalls. + */ +- nr &= __SYSCALL_MASK; +- if (likely(nr < NR_syscalls)) { ++ if (x32_enabled) { ++ nr &= ~__X32_SYSCALL_BIT; ++ if (unlikely(nr >= NR_syscalls)) ++ goto bad; + nr = array_index_nospec(nr, NR_syscalls); ++ goto good; ++ } else { ++ nr &= ~0U; ++ if (unlikely(nr >= NR_non_x32_syscalls)) ++ goto bad; ++ nr = array_index_nospec(nr, NR_non_x32_syscalls); ++good: + regs->ax = sys_call_table[nr](regs); + } +- ++bad: + syscall_return_slowpath(regs); + } + #endif +Index: linux/arch/x86/entry/syscall_64.c +=================================================================== +--- linux.orig/arch/x86/entry/syscall_64.c ++++ linux/arch/x86/entry/syscall_64.c +@@ -4,6 +4,9 @@ + #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 <asm/asm-offsets.h> + #include <asm/syscall.h> + +@@ -23,3 +26,50 @@ 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 */ ++ ++#if defined(CONFIG_X86_X32_DISABLED) ++DEFINE_STATIC_KEY_FALSE(x32_enabled_skey); ++#else ++DEFINE_STATIC_KEY_TRUE(x32_enabled_skey); ++#endif ++ ++static int __init x32_param_set(const char *val, const struct kernel_param *p) ++{ ++ bool enabled; ++ int ret; ++ ++ ret = kstrtobool(val, &enabled); ++ if (ret) ++ return ret; ++ if (IS_ENABLED(CONFIG_X86_X32_DISABLED)) { ++ if (enabled) { ++ static_key_enable(&x32_enabled_skey.key); ++ pr_info("Enabled x32 syscalls\n"); ++ } ++ } else { ++ if (!enabled) { ++ static_key_disable(&x32_enabled_skey.key); ++ pr_info("Disabled x32 syscalls\n"); ++ } ++ } ++ return 0; ++} ++ ++static int x32_param_get(char *buffer, const struct kernel_param *p) ++{ ++ return sprintf(buffer, "%c\n", ++ static_key_enabled(&x32_enabled_skey) ? 'Y' : 'N'); ++} ++ ++static const struct kernel_param_ops x32_param_ops = { ++ .set = x32_param_set, ++ .get = x32_param_get, ++}; ++ ++arch_param_cb(x32, &x32_param_ops, NULL, 0444); ++ ++#endif +Index: linux/arch/x86/include/asm/elf.h +=================================================================== +--- linux.orig/arch/x86/include/asm/elf.h ++++ linux/arch/x86/include/asm/elf.h +@@ -10,6 +10,7 @@ + #include <asm/ptrace.h> + #include <asm/user.h> + #include <asm/auxvec.h> ++#include <asm/syscall.h> + + typedef unsigned long elf_greg_t; + +@@ -163,7 +164,8 @@ do { \ + + #define compat_elf_check_arch(x) \ + (elf_check_arch_ia32(x) || \ +- (IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64)) ++ (IS_ENABLED(CONFIG_X86_X32_ABI) && x32_enabled && \ ++ (x)->e_machine == EM_X86_64)) + + #if __USER32_DS != __USER_DS + # error "The following code assumes __USER32_DS == __USER_DS" +Index: linux/arch/x86/include/asm/syscall.h +=================================================================== +--- linux.orig/arch/x86/include/asm/syscall.h ++++ linux/arch/x86/include/asm/syscall.h +@@ -16,6 +16,7 @@ + #include <uapi/linux/audit.h> + #include <linux/sched.h> + #include <linux/err.h> ++#include <linux/jump_label.h> + #include <asm/asm-offsets.h> /* For NR_syscalls */ + #include <asm/thread_info.h> /* for TS_COMPAT */ + #include <asm/unistd.h> +@@ -39,6 +40,18 @@ extern const sys_call_ptr_t sys_call_tab + extern const sys_call_ptr_t ia32_sys_call_table[]; + #endif + ++#if defined(CONFIG_X86_X32_ABI) ++#if defined(CONFIG_X86_X32_DISABLED) ++DECLARE_STATIC_KEY_FALSE(x32_enabled_skey); ++#define x32_enabled static_branch_unlikely(&x32_enabled_skey) ++#else ++DECLARE_STATIC_KEY_TRUE(x32_enabled_skey); ++#define x32_enabled static_branch_likely(&x32_enabled_skey) ++#endif ++#else ++#define x32_enabled 0 ++#endif ++ + /* + * Only the low 32 bits of orig_ax are meaningful, so we return int. + * This importantly ignores the high bits on 64-bit, so comparisons +Index: linux/arch/x86/include/asm/unistd.h +=================================================================== +--- linux.orig/arch/x86/include/asm/unistd.h ++++ linux/arch/x86/include/asm/unistd.h +@@ -6,9 +6,9 @@ + + + # ifdef CONFIG_X86_X32_ABI +-# define __SYSCALL_MASK (~(__X32_SYSCALL_BIT)) ++# define NR_non_x32_syscalls 512 + # else +-# define __SYSCALL_MASK (~0) ++# define NR_non_x32_syscalls NR_syscalls + # endif + + # ifdef CONFIG_X86_32 |