x86/entry: Make IA32 syscalls' availability depend on ia32_enabled()
authorNikolay Borisov <nik.borisov@suse.com>
Fri, 23 Jun 2023 11:14:08 +0000 (14:14 +0300)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 14 Sep 2023 11:19:53 +0000 (13:19 +0200)
Another major aspect of supporting running of 32bit processes is the
ability to access 32bit syscalls. Such syscalls can be invoked by
using the legacy int 0x80 handler and  sysenter/syscall instructions.

If IA32 emulation is disabled ensure that each of those 3 distinct
mechanisms are also disabled. For int 0x80 a #GP exception would be
generated since the respective descriptor is not going to be loaded at
all. Invoking sysenter will also result in a #GP since IA32_SYSENTER_CS
contains an invalid segment. Finally, syscall instruction cannot really
be disabled so it's configured to execute a minimal handler.

Signed-off-by: Nikolay Borisov <nik.borisov@suse.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20230623111409.3047467-6-nik.borisov@suse.com
arch/x86/include/asm/proto.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/idt.c

index 12ef86b19910d3b80050aa3553f1ae1ee2e19672..4d84122bd6433b165dff727887667965637ee7e4 100644 (file)
@@ -36,6 +36,9 @@ void entry_INT80_compat(void);
 #ifdef CONFIG_XEN_PV
 void xen_entry_INT80_compat(void);
 #endif
+#else /* !CONFIG_IA32_EMULATION */
+#define entry_SYSCALL_compat NULL
+#define entry_SYSENTER_compat NULL
 #endif
 
 void x86_configure_nx(void);
index b3f8cba21353edb238d9d2e66afaae17ba08f86d..afa755e06ae96f08dc9244b768033626273d6f76 100644 (file)
@@ -62,6 +62,7 @@
 #include <asm/intel-family.h>
 #include <asm/cpu_device_id.h>
 #include <asm/uv/uv.h>
+#include <asm/ia32.h>
 #include <asm/set_memory.h>
 #include <asm/traps.h>
 #include <asm/sev.h>
@@ -2074,24 +2075,24 @@ void syscall_init(void)
        wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
        wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
 
-#ifdef CONFIG_IA32_EMULATION
-       wrmsrl_cstar((unsigned long)entry_SYSCALL_compat);
-       /*
-        * This only works on Intel CPUs.
-        * On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
-        * This does not cause SYSENTER to jump to the wrong location, because
-        * AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
-        */
-       wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
-       wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
-                   (unsigned long)(cpu_entry_stack(smp_processor_id()) + 1));
-       wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
-#else
-       wrmsrl_cstar((unsigned long)entry_SYSCALL32_ignore);
-       wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
-       wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
-       wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
-#endif
+       if (ia32_enabled()) {
+               wrmsrl_cstar((unsigned long)entry_SYSCALL_compat);
+               /*
+                * This only works on Intel CPUs.
+                * On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
+                * This does not cause SYSENTER to jump to the wrong location, because
+                * AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
+                */
+               wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
+               wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
+                           (unsigned long)(cpu_entry_stack(smp_processor_id()) + 1));
+               wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
+       } else {
+               wrmsrl_cstar((unsigned long)entry_SYSCALL32_ignore);
+               wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
+               wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
+               wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
+       }
 
        /*
         * Flags to clear on syscall; clear as much as possible
index b786d48f5a0faf1ac944b10082be755a0813264e..8857abc706e469f73edf7f98953838eebdd05354 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/proto.h>
 #include <asm/desc.h>
 #include <asm/hw_irq.h>
+#include <asm/ia32.h>
 #include <asm/idtentry.h>
 
 #define DPL0           0x0
@@ -116,6 +117,9 @@ static const __initconst struct idt_data def_idts[] = {
 #endif
 
        SYSG(X86_TRAP_OF,               asm_exc_overflow),
+};
+
+static const struct idt_data ia32_idt[] __initconst = {
 #if defined(CONFIG_IA32_EMULATION)
        SYSG(IA32_SYSCALL_VECTOR,       entry_INT80_compat),
 #elif defined(CONFIG_X86_32)
@@ -225,6 +229,9 @@ void __init idt_setup_early_traps(void)
 void __init idt_setup_traps(void)
 {
        idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true);
+
+       if (ia32_enabled())
+               idt_setup_from_table(idt_table, ia32_idt, ARRAY_SIZE(ia32_idt), true);
 }
 
 #ifdef CONFIG_X86_64