1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/arch/x86/platform/efi/efi_thunk_64.S
Thadeu Lima de Souza Cascardo 51a6fa0732 efi/x86: use naked RET on mixed mode call wrapper
When running with return thunks enabled under 32-bit EFI, the system
crashes with:

  kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
  BUG: unable to handle page fault for address: 000000005bc02900
  #PF: supervisor instruction fetch in kernel mode
  #PF: error_code(0x0011) - permissions violation
  PGD 18f7063 P4D 18f7063 PUD 18ff063 PMD 190e063 PTE 800000005bc02063
  Oops: 0011 [#1] PREEMPT SMP PTI
  CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.19.0-rc6+ #166
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  RIP: 0010:0x5bc02900
  Code: Unable to access opcode bytes at RIP 0x5bc028d6.
  RSP: 0018:ffffffffb3203e10 EFLAGS: 00010046
  RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000048
  RDX: 000000000190dfac RSI: 0000000000001710 RDI: 000000007eae823b
  RBP: ffffffffb3203e70 R08: 0000000001970000 R09: ffffffffb3203e28
  R10: 747563657865206c R11: 6c6977203a696665 R12: 0000000000001710
  R13: 0000000000000030 R14: 0000000001970000 R15: 0000000000000001
  FS:  0000000000000000(0000) GS:ffff8e013ca00000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0018 ES: 0018 CR0: 0000000080050033
  CR2: 000000005bc02900 CR3: 0000000001930000 CR4: 00000000000006f0
  Call Trace:
   ? efi_set_virtual_address_map+0x9c/0x175
   efi_enter_virtual_mode+0x4a6/0x53e
   start_kernel+0x67c/0x71e
   x86_64_start_reservations+0x24/0x2a
   x86_64_start_kernel+0xe9/0xf4
   secondary_startup_64_no_verify+0xe5/0xeb

That's because it cannot jump to the return thunk from the 32-bit code.

Using a naked RET and marking it as safe allows the system to proceed
booting.

Fixes: aa3d480315 ("x86: Use return-thunk in asm code")
Reported-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Cc: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: <stable@vger.kernel.org>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2022-07-16 09:51:24 -07:00

91 lines
2.1 KiB
ArmAsm

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
*
* Support for invoking 32-bit EFI runtime services from a 64-bit
* kernel.
*
* The below thunking functions are only used after ExitBootServices()
* has been called. This simplifies things considerably as compared with
* the early EFI thunking because we can leave all the kernel state
* intact (GDT, IDT, etc) and simply invoke the 32-bit EFI runtime
* services from __KERNEL32_CS. This means we can continue to service
* interrupts across an EFI mixed mode call.
*
* We do however, need to handle the fact that we're running in a full
* 64-bit virtual address space. Things like the stack and instruction
* addresses need to be accessible by the 32-bit firmware, so we rely on
* using the identity mappings in the EFI page table to access the stack
* and kernel text (see efi_setup_page_tables()).
*/
#include <linux/linkage.h>
#include <linux/objtool.h>
#include <asm/page_types.h>
#include <asm/segment.h>
#include <asm/nospec-branch.h>
.text
.code64
SYM_FUNC_START(__efi64_thunk)
STACK_FRAME_NON_STANDARD __efi64_thunk
push %rbp
push %rbx
/*
* Switch to 1:1 mapped 32-bit stack pointer.
*/
movq %rsp, %rax
movq efi_mixed_mode_stack_pa(%rip), %rsp
push %rax
/*
* Copy args passed via the stack
*/
subq $0x24, %rsp
movq 0x18(%rax), %rbp
movq 0x20(%rax), %rbx
movq 0x28(%rax), %rax
movl %ebp, 0x18(%rsp)
movl %ebx, 0x1c(%rsp)
movl %eax, 0x20(%rsp)
/*
* Calculate the physical address of the kernel text.
*/
movq $__START_KERNEL_map, %rax
subq phys_base(%rip), %rax
leaq 1f(%rip), %rbp
leaq 2f(%rip), %rbx
subq %rax, %rbp
subq %rax, %rbx
movl %ebx, 0x0(%rsp) /* return address */
movl %esi, 0x4(%rsp)
movl %edx, 0x8(%rsp)
movl %ecx, 0xc(%rsp)
movl %r8d, 0x10(%rsp)
movl %r9d, 0x14(%rsp)
/* Switch to 32-bit descriptor */
pushq $__KERNEL32_CS
pushq %rdi /* EFI runtime service address */
lretq
1: movq 0x20(%rsp), %rsp
pop %rbx
pop %rbp
ANNOTATE_UNRET_SAFE
ret
int3
.code32
2: pushl $__KERNEL_CS
pushl %ebp
lret
SYM_FUNC_END(__efi64_thunk)
.bss
.balign 8
SYM_DATA(efi_mixed_mode_stack_pa, .quad 0)