x86/entry: Convert INT 0x80 emulation to IDTENTRY
authorThomas Gleixner <tglx@linutronix.de>
Mon, 4 Dec 2023 08:31:39 +0000 (11:31 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Dec 2023 17:45:02 +0000 (18:45 +0100)
[ upstream commit be5341eb0d43b1e754799498bd2e8756cc167a41 ]

There is no real reason to have a separate ASM entry point implementation
for the legacy INT 0x80 syscall emulation on 64-bit.

IDTENTRY provides all the functionality needed with the only difference
that it does not:

  - save the syscall number (AX) into pt_regs::orig_ax
  - set pt_regs::ax to -ENOSYS

Both can be done safely in the C code of an IDTENTRY before invoking any of
the syscall related functions which depend on this convention.

Aside of ASM code reduction this prepares for detecting and handling a
local APIC injected vector 0x80.

[ kirill.shutemov: More verbose comments ]
Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: <stable@vger.kernel.org> # v6.0+
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/entry/common.c
arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/idtentry.h
arch/x86/include/asm/proto.h
arch/x86/kernel/idt.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/xen-asm.S

index 4cec389854142788331ac4693995790cc74266ae..0f22a037be661c2b858472311dd5425458cbbfce 100644 (file)
@@ -119,7 +119,62 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
        }
 }
 
-/* Handles int $0x80 */
+#ifdef CONFIG_IA32_EMULATION
+/**
+ * int80_emulation - 32-bit legacy syscall entry
+ *
+ * This entry point can be used by 32-bit and 64-bit programs to perform
+ * 32-bit system calls.  Instances of INT $0x80 can be found inline in
+ * various programs and libraries.  It is also used by the vDSO's
+ * __kernel_vsyscall fallback for hardware that doesn't support a faster
+ * entry method.  Restarted 32-bit system calls also fall back to INT
+ * $0x80 regardless of what instruction was originally used to do the
+ * system call.
+ *
+ * This is considered a slow path.  It is not used by most libc
+ * implementations on modern hardware except during process startup.
+ *
+ * The arguments for the INT $0x80 based syscall are on stack in the
+ * pt_regs structure:
+ *   eax:                              system call number
+ *   ebx, ecx, edx, esi, edi, ebp:     arg1 - arg 6
+ */
+DEFINE_IDTENTRY_RAW(int80_emulation)
+{
+       int nr;
+
+       /* Establish kernel context. */
+       enter_from_user_mode(regs);
+
+       instrumentation_begin();
+       add_random_kstack_offset();
+
+       /*
+        * The low level idtentry code pushed -1 into regs::orig_ax
+        * and regs::ax contains the syscall number.
+        *
+        * User tracing code (ptrace or signal handlers) might assume
+        * that the regs::orig_ax contains a 32-bit number on invoking
+        * a 32-bit syscall.
+        *
+        * Establish the syscall convention by saving the 32bit truncated
+        * syscall number in regs::orig_ax and by invalidating regs::ax.
+        */
+       regs->orig_ax = regs->ax & GENMASK(31, 0);
+       regs->ax = -ENOSYS;
+
+       nr = syscall_32_enter(regs);
+
+       local_irq_enable();
+       nr = syscall_enter_from_user_mode_work(regs, nr);
+       do_syscall_32_irqs_on(regs, nr);
+
+       instrumentation_end();
+       syscall_exit_to_user_mode(regs);
+}
+#else /* CONFIG_IA32_EMULATION */
+
+/* Handles int $0x80 on a 32bit kernel */
 __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
        int nr = syscall_32_enter(regs);
@@ -138,6 +193,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
        instrumentation_end();
        syscall_exit_to_user_mode(regs);
 }
+#endif /* !CONFIG_IA32_EMULATION */
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
index 70150298f8bdf5ea1cfa9f895a0443b521e5b60b..4e88f84387061b6bd30edcf290eee247a04b573d 100644 (file)
@@ -276,80 +276,3 @@ SYM_INNER_LABEL(entry_SYSRETL_compat_end, SYM_L_GLOBAL)
        ANNOTATE_NOENDBR
        int3
 SYM_CODE_END(entry_SYSCALL_compat)
-
-/*
- * 32-bit legacy system call entry.
- *
- * 32-bit x86 Linux system calls traditionally used the INT $0x80
- * instruction.  INT $0x80 lands here.
- *
- * This entry point can be used by 32-bit and 64-bit programs to perform
- * 32-bit system calls.  Instances of INT $0x80 can be found inline in
- * various programs and libraries.  It is also used by the vDSO's
- * __kernel_vsyscall fallback for hardware that doesn't support a faster
- * entry method.  Restarted 32-bit system calls also fall back to INT
- * $0x80 regardless of what instruction was originally used to do the
- * system call.
- *
- * This is considered a slow path.  It is not used by most libc
- * implementations on modern hardware except during process startup.
- *
- * Arguments:
- * eax  system call number
- * ebx  arg1
- * ecx  arg2
- * edx  arg3
- * esi  arg4
- * edi  arg5
- * ebp  arg6
- */
-SYM_CODE_START(entry_INT80_compat)
-       UNWIND_HINT_ENTRY
-       ENDBR
-       /*
-        * Interrupts are off on entry.
-        */
-       ASM_CLAC                        /* Do this early to minimize exposure */
-       ALTERNATIVE "swapgs", "", X86_FEATURE_XENPV
-
-       /*
-        * User tracing code (ptrace or signal handlers) might assume that
-        * the saved RAX contains a 32-bit number when we're invoking a 32-bit
-        * syscall.  Just in case the high bits are nonzero, zero-extend
-        * the syscall number.  (This could almost certainly be deleted
-        * with no ill effects.)
-        */
-       movl    %eax, %eax
-
-       /* switch to thread stack expects orig_ax and rdi to be pushed */
-       pushq   %rax                    /* pt_regs->orig_ax */
-
-       /* Need to switch before accessing the thread stack. */
-       SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
-
-       /* In the Xen PV case we already run on the thread stack. */
-       ALTERNATIVE "", "jmp .Lint80_keep_stack", X86_FEATURE_XENPV
-
-       movq    %rsp, %rax
-       movq    PER_CPU_VAR(pcpu_hot + X86_top_of_stack), %rsp
-
-       pushq   5*8(%rax)               /* regs->ss */
-       pushq   4*8(%rax)               /* regs->rsp */
-       pushq   3*8(%rax)               /* regs->eflags */
-       pushq   2*8(%rax)               /* regs->cs */
-       pushq   1*8(%rax)               /* regs->ip */
-       pushq   0*8(%rax)               /* regs->orig_ax */
-.Lint80_keep_stack:
-
-       PUSH_AND_CLEAR_REGS rax=$-ENOSYS
-       UNWIND_HINT_REGS
-
-       cld
-
-       IBRS_ENTER
-       UNTRAIN_RET
-
-       movq    %rsp, %rdi
-       call    do_int80_syscall_32
-       jmp     swapgs_restore_regs_and_return_to_usermode
-SYM_CODE_END(entry_INT80_compat)
index 05fd175cec7d5c9a617fd1f3c1462ade1d44b06e..13639e57e1f8af4c24c0c656a9f0801516bf25f4 100644 (file)
@@ -569,6 +569,10 @@ DECLARE_IDTENTRY_RAW(X86_TRAP_UD,          exc_invalid_op);
 DECLARE_IDTENTRY_RAW(X86_TRAP_BP,              exc_int3);
 DECLARE_IDTENTRY_RAW_ERRORCODE(X86_TRAP_PF,    exc_page_fault);
 
+#if defined(CONFIG_IA32_EMULATION)
+DECLARE_IDTENTRY_RAW(IA32_SYSCALL_VECTOR,      int80_emulation);
+#endif
+
 #ifdef CONFIG_X86_MCE
 #ifdef CONFIG_X86_64
 DECLARE_IDTENTRY_MCE(X86_TRAP_MC,      exc_machine_check);
index 12ef86b19910d3b80050aa3553f1ae1ee2e19672..84294b66b91625e9ec22cc65cc49e80ecf5dc1e8 100644 (file)
@@ -32,10 +32,6 @@ void entry_SYSCALL_compat(void);
 void entry_SYSCALL_compat_safe_stack(void);
 void entry_SYSRETL_compat_unsafe_stack(void);
 void entry_SYSRETL_compat_end(void);
-void entry_INT80_compat(void);
-#ifdef CONFIG_XEN_PV
-void xen_entry_INT80_compat(void);
-#endif
 #endif
 
 void x86_configure_nx(void);
index b786d48f5a0faf1ac944b10082be755a0813264e..fc77a96040b7ea354bc4319b3edbe4dbe4290483 100644 (file)
@@ -117,7 +117,7 @@ static const __initconst struct idt_data def_idts[] = {
 
        SYSG(X86_TRAP_OF,               asm_exc_overflow),
 #if defined(CONFIG_IA32_EMULATION)
-       SYSG(IA32_SYSCALL_VECTOR,       entry_INT80_compat),
+       SYSG(IA32_SYSCALL_VECTOR,       asm_int80_emulation),
 #elif defined(CONFIG_X86_32)
        SYSG(IA32_SYSCALL_VECTOR,       entry_INT80_32),
 #endif
index bbbfdd495ebd3ac590fd152e0504c6bedae611de..aeb33e0a3f763370b00daf427063b2010f0bcf40 100644 (file)
@@ -704,7 +704,7 @@ static struct trap_array_entry trap_array[] = {
        TRAP_ENTRY(exc_int3,                            false ),
        TRAP_ENTRY(exc_overflow,                        false ),
 #ifdef CONFIG_IA32_EMULATION
-       { entry_INT80_compat,          xen_entry_INT80_compat,          false },
+       TRAP_ENTRY(int80_emulation,                     false ),
 #endif
        TRAP_ENTRY(exc_page_fault,                      false ),
        TRAP_ENTRY(exc_divide_error,                    false ),
index 9e5e680087853a34f8a2fc7a935e60e2c28f12d5..1a9cd18dfbd31208e5d1bcfa53f4a6e90bc81cf6 100644 (file)
@@ -156,7 +156,7 @@ xen_pv_trap asm_xenpv_exc_machine_check
 #endif /* CONFIG_X86_MCE */
 xen_pv_trap asm_exc_simd_coprocessor_error
 #ifdef CONFIG_IA32_EMULATION
-xen_pv_trap entry_INT80_compat
+xen_pv_trap asm_int80_emulation
 #endif
 xen_pv_trap asm_exc_xen_unknown_trap
 xen_pv_trap asm_exc_xen_hypervisor_callback