[PATCH RFC 0/8] Add efi page fault handler to fix/recover from

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Sai Praneeth <sai.praneeth.prakhya@xxxxxxxxx>

There may exist some buggy UEFI firmware implementations that access efi
memory regions other than EFI_RUNTIME_SERVICES_<CODE/DATA> even after
kernel has assumed control of the platform. This violates UEFI
specification. Here, we provide a debug config option which when enabled
detects and fixes up/recovers from page faults caused by buggy firmware.

The above said illegal accesses trigger page fault in ring 0 because
firmware executes at ring 0 and if unhandled it hangs the kernel. We
provide an efi specific page fault handler to:
1. Avoid panics/hangs caused by buggy firmware.
2. Shout loud that the firmware is buggy and hence can save ourselves
from being blamed for not a fault of ours.

Depending on the illegally accessed efi region, the efi page fault
handler handles illegal accesses differently.
1. If the illegally accessed region is EFI_BOOT_SERVICES_<CODE/DATA>,
the page fault handler fixes it up by mapping the requested region.
2. If the illegally accessed region is any other efi region (like
EFI_CONVENTIONAL_MEMORY or EFI_LOADER_<CODE/DATA>), the page fault
handler exits firmware context and disables EFI Runtime Services, so
that we will never again call buggy firmware.

Page faults to efi regions are handled differently because, presently
during kernel boot, EFI_BOOT_SERVICES_<CODE/DATA> regions are reserved
by kernel and hence it's OK to dynamically map these regions in page
fault handler. The same approach cannot be followed for other efi
regions like EFI_CONVENTIONAL_MEMORY and EFI_LOADER_<CODE/DATA> as they
are very huge in size and reserving them could make the kernel
un-bootable. Hence, we take a different approach (exiting firmware
context) while dealing with page faults to these regions. This also
saves us from executing buggy firmware further.

Exiting firmware context means that on every entry to firmware we save
the kernel context before calling firmware and if the firmware
misbehaves, in the page fault handler, we roll back to the saved kernel
context. Saving kernel context means saving the stack pointer and the
instruction that gets executed when firmware returns. In the page fault
handler we fix up these two things (RIP and RSP) so that when returning
from page fault handler it looks as if firmware has called RET.

This issue was reported by Al Stone when he saw that reboot via EFI hangs
the machine. Upon debugging, I found that it's efi_reset_system() that's
touching memory regions which it shouldn't. To reproduce the same
behavior, I have hacked OVMF and made efi_reset_system() buggy.

Testing the patch set:
----------------------
1. Download buggy firmware from here [1].
2. Run a qemu instance with this buggy BIOS and boot mainline kernel.
Add reboot=efi to the kernel command line arguments and after the kernel
is up and running, type "reboot". The kernel should hang while rebooting.
3. With the same setup, boot kernel after applying patches and the
reboot should work fine. Also please notice warning/error messages
printed by kernel.

Note:
-----
Patch set based on "next" branch in efi tree.

[1] https://drive.google.com/open?id=1tkvT7GaVX2zSlzy1HK1T4Tv8cT36GP6R

Sai Praneeth (8):
  x86/efi: Remove __init attribute from memory mapping functions
  x86/efi: Permanently save the EFI_MEMORY_MAP passed by firmware
  x86/efi: Save kernel context before calling EFI Runtime Services
  x86/efi: Add page fault handler to fixup/recover from page faults
    caused by firmware
  x86/efi: If EFI_WARN_ON_ILLEGAL_ACCESSES is enabled don't call
    efi_free_boot_services()
  x86/efi: Map EFI_BOOT_SERVICES_<CODE/DATA> regions only when
    EFI_WARN_ON_ILLEGAL_ACCESSES is disabled
  x86/mm: If in_atomic(), allocate pages without sleeping
  x86/efi: Introduce EFI_WARN_ON_ILLEGAL_ACCESSES

 arch/x86/Kconfig                        |  17 +++
 arch/x86/include/asm/efi.h              |  42 ++++++-
 arch/x86/mm/fault.c                     |   9 ++
 arch/x86/mm/pageattr.c                  |  16 ++-
 arch/x86/platform/efi/efi.c             |  10 +-
 arch/x86/platform/efi/efi_32.c          |   2 +-
 arch/x86/platform/efi/efi_64.c          |  16 ++-
 arch/x86/platform/efi/efi_stub_64.S     | 101 ++++++++++++++++-
 arch/x86/platform/efi/quirks.c          | 193 ++++++++++++++++++++++++++++++++
 drivers/firmware/efi/efi.c              |   6 +-
 drivers/firmware/efi/runtime-wrappers.c |   6 +
 include/linux/efi.h                     |  16 ++-
 init/main.c                             |   3 +-
 13 files changed, 415 insertions(+), 22 deletions(-)

Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@xxxxxxxxx>
Suggested-by: Matt Fleming <matt@xxxxxxxxxxxxxxxxxxx>
Based-on-code-from: Ricardo Neri <ricardo.neri@xxxxxxxxx>
Cc: Al Stone <astone@xxxxxxxxxx>
Cc: Lee Chun-Yi <jlee@xxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxxxx>
Cc: Bhupesh Sharma <bhsharma@xxxxxxxxxx>
Cc: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>

-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux