#include <linux/syscalls.h>
#include <linux/entry-common.h>
#include <linux/nospec.h>
+#include <linux/moduleparam.h>
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "syscall."
#include <asm/syscall.h>
#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
*/
unsigned int xnr = nr - __X32_SYSCALL_BIT;
- if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
+ if (IS_ENABLED(CONFIG_X86_X32_ABI) && unlikely(x32_enabled) && likely(xnr < X32_NR_syscalls)) {
xnr = array_index_nospec(xnr, X32_NR_syscalls);
regs->ax = x32_sys_call(regs, xnr);
return true;
/* Use SYSRET to exit to userspace */
return true;
}
+
+#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
#include <asm/user.h>
#include <asm/auxvec.h>
#include <asm/fsgsbase.h>
+#ifndef COMPILE_OFFSETS /* avoid a circular dependency on asm-offsets.h */
+#include <asm/syscall.h>
+#endif
typedef unsigned long elf_greg_t;
#define compat_elf_check_arch(x) \
((elf_check_arch_ia32(x) && ia32_enabled_verbose()) || \
- (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))
static inline void elf_common_init(struct thread_struct *t,
struct pt_regs *regs, const u16 ds)
#include <uapi/linux/audit.h>
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/jump_label.h>
#include <asm/thread_info.h> /* for TS_COMPAT */
#include <asm/unistd.h>
extern long x32_sys_call(const struct pt_regs *, unsigned int nr);
extern long x64_sys_call(const struct pt_regs *, unsigned int nr);
+#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