[PATCH RFC 7/8] x86/mm: If in_atomic(), allocate pages without sleeping

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

A page fault occurs when any EFI Runtime Service tries to reference a
memory region which it shouldn't. If the illegally accessed region
is EFI_BOOT_SERVICES_, the efi specific page fault handler
fixes it up by dynamically creating VA->PA mappings using
efi_map_region().

Originally, efi_map_region() and hence the functionality of creating
mappings for efi regions was intended to be used *only* during boot time
(please note __init modifier) and hence when called during runtime,
the page allocators complain. Calling efi_map_region() during runtime
complains because "gfp_allowed_mask" value changes from boot time to
runtime (GFP_BOOT_MASK to __GFP_BITS_MASK). During boot, even though
efi_map_region() calls alloc__page with GFP_KERNEL, the page
allocator doesn't complain because "__GFP_RECLAIM" flag is cleared by
"gfp_allowed_mask", but during runtime it isn't cleared and hence prints
below stack trace.

BUG: sleeping function called from invalid context at mm/page_alloc.c:4320
in_atomic(): 1, irqs_disabled(): 1, pid: 2022, name: fwts
1 lock held by fwts/2022:
irq event stamp: 45714
hardirqs last  enabled at (45713): [] 
restore_regs_and_return_to_kernel+0x0/0x2c
hardirqs last disabled at (45714): [] error_entry+0x7c/0x100
softirqs last  enabled at (44732): [] __do_softirq+0x387/0x49a
softirqs last disabled at (44707): [] irq_exit+0xbb/0xc0
CPU: 0 PID: 2022 Comm: fwts Not tainted 4.17.0-rc4-efitest+ #405
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
Call Trace:
dump_stack+0x5e/0x8b
___might_sleep+0x20c/0x240
__alloc_pages_nodemask+0xc2/0x330
get_zeroed_page+0x12/0x40
alloc_pmd_page+0x13/0x50
populate_pmd+0xc0/0x2e0
? __lock_acquire+0x439/0x740
__cpa_process_fault+0x2e1/0x5d0
__change_page_attr_set_clr+0x7c3/0xcd0
? console_unlock+0x34d/0x660
? kernel_map_pages_in_pgd+0x8c/0x160
kernel_map_pages_in_pgd+0x8c/0x160
? printk+0x43/0x4b
? __map_region+0x3c/0x60
__map_region+0x3c/0x60
efi_map_region+0x83/0xd0
efi_illegal_accesses_fixup+0x1ca/0x1e0
no_context+0x112/0x390
__do_page_fault+0xc7/0x4f0
page_fault+0x1e/0x30
RIP: 0010:0xfffeffc7ccf1
RSP: 0018:c975bbf0 EFLAGS: 00010282
RAX: 0048 RBX: c975be10 RCX: c975bad0
RDX: 03f8 RSI: c975be10 RDI: fffeffc7cccf
RBP: c975bdc8 R08: 0048 R09: 0048
R10: 03fd R11: 03f8 R12: 880032a92d80
R13: 0003 R14: 7ffcf1eb9d50 R15: 
? efi_call+0xd1/0x160
? __lock_acquire+0x439/0x740
? _raw_spin_unlock+0x24/0x30
? virt_efi_get_next_high_mono_count+0x77/0xf0
? efi_test_ioctl+0x1ab/0xc20
? selinux_file_ioctl+0x122/0x1c0
? do_vfs_ioctl+0x92/0x6b0
? do_vfs_ioctl+0x92/0x6b0
? security_file_ioctl+0x3c/0x50
? selinux_capable+0x20/0x20
? ksys_ioctl+0x66/0x70
? __x64_sys_ioctl+0x16/0x20
? do_syscall_64+0x50/0x170
? entry_SYSCALL_64_after_hwframe+0x49/0xbe

I guess, we can't do much to fix the above warning except to change
the allocation conditionally from GFP_KERNEL to GFP_ATOMIC, so that
we could use efi_map_region() during runtime. This change shouldn't
effect any other generic page allocations because this allocation is
used only by efi functions [1].

[1] Comment in __cpa_process_fault() at arch/x86/mm/pageattr.c

if (cpa->pgd) {
/*
 * Right now, we only execute this code path when mapping
 * the EFI virtual memory map regions, no other users
 * provide a ->pgd value. This may change in the future.
 */
return populate_pgd(cpa, vaddr);
}

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/mm/pageattr.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 3bded76e8d5c..1b28a333c8ce 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -926,7 +926,13 @@ static void unmap_pud_range(p4d_t *p4d, unsigned long 
start, unsigned long end)
 
 static int alloc_pte_page(pmd_t *pmd)
 {
-   pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL);
+   pte_t *pte;
+
+   if (in_atomic())
+   pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
+   else
+   pte = (pte_t *)get_zeroed_page(GFP_KERNEL);
+
if (!pte)
return -1;
 
@@ -936,7 +942,13 @@ static int alloc_pte_page(pmd_t *pmd)
 
 static int alloc_pmd_page(pud_t *pud)
 {
-   pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL);
+   pmd_t *pmd;
+
+   if (in_atomic())
+   pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
+   else
+   pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL);
+
if (!pmd)
return -1;
 
-- 
2.7.4

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

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

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

There may exist some buggy UEFI firmware implementations that access efi
memory regions other than EFI_RUNTIME_SERVICES_ 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_,
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_), 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_ 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_ 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_ 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 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 

-- 
2.7.4

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


[PATCH RFC 2/8] x86/efi: Permanently save the EFI_MEMORY_MAP passed by firmware

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

The page fault handler that fixes up page faults caused by firmware
needs the original memory map passed by firmware. It looks up this
memory map to find the type of the memory region at which the page fault
occurred. Presently, EFI subsystem discards the original memory map
passed by firmware and replaces it with a new memory map that has only
EFI_RUNTIME_SERVICES_ regions, but illegal accesses by
firmware can occur at any region. Hence, _only_ if
CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES is defined, create a backup of the
original memory map passed by firmware, so that we can detect/fix
illegal accesses to *any* efi regions.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/include/asm/efi.h |  6 ++
 arch/x86/platform/efi/efi.c|  2 ++
 arch/x86/platform/efi/quirks.c | 49 ++
 3 files changed, 57 insertions(+)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 9b70743400f3..c97f2e955cab 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -142,6 +142,12 @@ extern int __init efi_reuse_config(u64 tables, int 
nr_tables);
 extern void efi_delete_dummy_variable(void);
 extern void efi_switch_mm(struct mm_struct *mm);
 
+#ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES
+extern void __init efi_save_original_memmap(void);
+#else
+static inline void __init efi_save_original_memmap(void) { }
+#endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES */
+
 struct efi_setup_data {
u64 fw_vendor;
u64 runtime;
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 439c2c40bf03..7d18b7ed5d41 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -946,6 +946,8 @@ static void __init __efi_enter_virtual_mode(void)
 
pa = __pa(new_memmap);
 
+   efi_save_original_memmap();
+
/*
 * Unregister the early EFI memmap from efi_init() and install
 * the new EFI memory map that we are about to pass to the
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 844d31cb8a0c..84b213a1460a 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -654,3 +654,52 @@ int efi_capsule_setup_info(struct capsule_info *cap_info, 
void *kbuff,
 }
 
 #endif
+
+#ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES
+
+static bool original_memory_map_present;
+static struct efi_memory_map original_memory_map;
+
+/*
+ * The page fault handler that fixes up page faults caused by buggy
+ * firmware needs original memory map (memory map passed by firmware).
+ * Hence, build a new EFI memmap that has *all* entries and save it for
+ * later use.
+ */
+void __init efi_save_original_memmap(void)
+{
+   efi_memory_desc_t *md;
+   void *remapped_phys, *new_md;
+   phys_addr_t new_phys, new_size;
+
+   new_size = efi.memmap.desc_size * efi.memmap.nr_map;
+   new_phys = efi_memmap_alloc(efi.memmap.nr_map);
+   if (!new_phys) {
+   pr_err("Failed to allocate new EFI memmap\n");
+   return;
+   }
+
+   remapped_phys = memremap(new_phys, new_size, MEMREMAP_WB);
+   if (!remapped_phys) {
+   pr_err("Failed to remap new EFI memmap\n");
+   __free_pages(pfn_to_page(PHYS_PFN(new_phys)), 
get_order(new_size));
+   return;
+   }
+
+   new_md = remapped_phys;
+   for_each_efi_memory_desc(md) {
+   memcpy(new_md, md, efi.memmap.desc_size);
+   new_md += efi.memmap.desc_size;
+   }
+
+   original_memory_map.late = 1;
+   original_memory_map.phys_map = new_phys;
+   original_memory_map.map = remapped_phys;
+   original_memory_map.nr_map = efi.memmap.nr_map;
+   original_memory_map.desc_size = efi.memmap.desc_size;
+   original_memory_map.map_end = remapped_phys + new_size;
+   original_memory_map.desc_version = efi.memmap.desc_version;
+
+   original_memory_map_present = true;
+}
+#endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES */
-- 
2.7.4

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


[PATCH RFC 5/8] x86/efi: If EFI_WARN_ON_ILLEGAL_ACCESSES is enabled don't call efi_free_boot_services()

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

During early boot phase EFI_BOOT_SERVICES_ regions are marked
as reserved by kernel (see efi_reserve_boot_services()) and hence are
not used by kernel for boot purposes. When EFI_WARN_ON_ILLEGAL_ACCESSES
is enabled, page faults triggered by firmware due to illegal accesses to
EFI_BOOT_SERVICES_ regions are dynamically fixed by kernel by
mapping these regions on demand. This resolution assumes that
EFI_BOOT_SERVICES_ regions are intact i.e. no one has ever
used these regions except firmware. Hence, to make this assumption true,
don't call efi_free_boot_services() if EFI_WARN_ON_ILLEGAL_ACCESSES is
enabled.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 init/main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/init/main.c b/init/main.c
index 3b4ada11ed52..dce0520861a1 100644
--- a/init/main.c
+++ b/init/main.c
@@ -730,7 +730,8 @@ asmlinkage __visible void __init start_kernel(void)
arch_post_acpi_subsys_init();
sfi_init_late();
 
-   if (efi_enabled(EFI_RUNTIME_SERVICES)) {
+   if (efi_enabled(EFI_RUNTIME_SERVICES) &&
+   !IS_ENABLED(CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES)) {
efi_free_boot_services();
}
 
-- 
2.7.4

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


[PATCH RFC 3/8] x86/efi: Save kernel context before calling EFI Runtime Services

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

After the kernel is up and running, the only time firmware executes is
when an EFI Runtime Service is invoked by kernel. When invoked, some
buggy implementations of EFI Runtime Service could access memory regions
which it shouldn't. This will cause a page fault in ring 0 and if
unhandled it hangs the kernel.

The obvious way to avoid such hangs is to handle the page fault.
Remember the sequence of things that lead us to page fault.
1. A user has requested kernel to execute some EFI Runtime Service
2. Kernel prepares and calls requested EFI Runtime Service
3. Requested EFI Runtime Service is buggy and hence caused a page fault
4. The kernel gets back control and it's in interrupt mode
If the page fault is handled successfully kernel would be returning
control to EFI Runtime Service which in turn returns control back to
kernel. But the kernel cannot map the requested efi region because it's
long gone. We cannot either mark EFI regions as reserved and dynamically
allow access because it will make the kernel un-bootable.

The proposed solution here is to save the kernel context before giving
away control to firmware (i.e. in step 2) and if the firmware
misbehaves, in the page fault handler, we roll back to the saved kernel
context. This saves us from executing buggy firmware further and saving
ourselves from hanging.

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.

UEFI specification v2.7, section 2.3.4 "Calling Conventions for X64
platforms" says that "The registers RBX, RBP, RDI, RSI, R12, R13, R14,
R15, and XMM6-XMM15 are considered nonvolatile and must be saved and
restored by a function that uses them". This means that any EFI Runtime
Service that uses the above mentioned registers will save/restore its
value. Hence, to emulate the same behaviour we save/restore these
registers each and every time we call EFI Runtime Service.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/include/asm/efi.h  |   3 ++
 arch/x86/platform/efi/efi_64.c  |   7 +++
 arch/x86/platform/efi/efi_stub_64.S | 101 +++-
 arch/x86/platform/efi/quirks.c  |   4 ++
 4 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index c97f2e955cab..47202b9e1b8e 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -121,6 +121,9 @@ extern void __iomem *__efi_init_fixup efi_ioremap(unsigned 
long addr,
 
 #endif /* CONFIG_X86_32 */
 
+extern u64 xmm_regs_rsp;
+extern u64 core_regs_rsp;
+extern u64 exit_fw_ctx_rip;
 extern struct efi_scratch efi_scratch;
 extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
 extern int __init efi_memblock_x86_reserve_range(void);
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index a04298312fdd..7787bc2e58fb 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -627,6 +627,13 @@ void __init efi_dump_pagetable(void)
  */
 void efi_switch_mm(struct mm_struct *mm)
 {
+   /*
+* Used by efi page fault handler (efi_illegal_accesses_fixup()) to
+* check if it was indeed invoked in firmware context.
+*/
+   xmm_regs_rsp = 0;
+   exit_fw_ctx_rip = 0;
+
task_lock(current);
efi_scratch.prev_mm = current->active_mm;
current->active_mm = mm;
diff --git a/arch/x86/platform/efi/efi_stub_64.S 
b/arch/x86/platform/efi/efi_stub_64.S
index 74628ec78f29..c86825c01b4c 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -39,6 +39,101 @@
mov %rsi, %cr0; \
mov (%rsp), %rsp
 
+#define SAVE_CORE_REGS_CALLEE  \
+   pushq %rbx; \
+   pushq %rdi; \
+   pushq %rsi; \
+   pushq %r12; \
+   pushq %r13; \
+   pushq %r14; \
+   pushq %r15
+
+#define RESTORE_CORE_REGS_CALLEE   \
+   popq %r15;  \
+   popq %r14;  \
+   popq %r13;  \
+   popq %r12;  \
+   popq %rsi;  \
+   popq %rdi;  \
+   popq %rbx
+
+#define SAVE_XMM_REGS_CALLEE   \
+   subq $0xb0, %rsp;   \
+   and $~0xf, %rsp ;   \
+   movaps %xmm6, 0xa0(%rsp);   \
+   movaps %xmm7, 0x90(%rsp);   \
+   movaps %xmm8, 0x80(%rsp);   \
+   movaps %xmm9, 0x70(%rsp);   \
+   movaps 

[PATCH RFC 4/8] x86/efi: Add page fault handler to fixup/recover from page faults caused by firmware

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

EFI regions could briefly be divided into 3 types.
1. EFI_BOOT_SERVICES_ regions
2. EFI_RUNTIME_SERVICES_ regions
3. Other EFI regions like EFI_LOADER_ etc.

As per the UEFI specification, after the call to ExitBootServices(),
accesses by firmware to any memory region except
EFI_RUNTIME_SERVICES_ regions is considered illegal. A buggy
firmware could trigger these illegal accesses during boot time or at
runtime (i.e. when the kernel is up and running). Presently, the kernel
can fix up illegal accesses to EFI_BOOT_SERVICES_ regions
*only* during kernel boot phase. If firmware triggers illegal accesses
to *any* other EFI regions during kernel boot, the kernel panics or if
this happens during kernel runtime then the kernel hangs.

Kernel panics/hangs because the memory region requested by firmware
isn't mapped which causes a page fault in ring 0 and the kernel fails to
handle it leading to die(). To save kernel from hanging we add a page
fault handler which detects illegal accesses by firmware and
1. If the illegally accessed region is EFI_BOOT_SERVICES_,
the kernel fixes it up by mapping the requested region.
2. If any other region (Eg: EFI_CONVENTIONAL_MEMORY or
EFI_LOADER_), then the kernel exits firmware context and
disables EFI Runtime Services, so that we will never again call buggy
firmware.

Illegal accesses to EFI_BOOT_SERVICES_ and to other regions
are dealt differently in efi page fault handler because presently during
kernel boot EFI_BOOT_SERVICES_ regions are reserved by kernel
and hence it's OK to dynamically map these regions in page fault
handler. We cannot reserve other EFI regions like
EFI_CONVENTIONAL_MEMORY and EFI_LOADER_ as they are very huge
in size and reserving them will make the kernel un-bootable. Hence, we
take a different approach (exiting firmware context) in dealing with
page faults to these regions.

The efi specific page fault handler offers us two advantages:
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.

Finally, this new mapping will not impact a reboot from kexec, as kexec
is only concerned about runtime memory regions.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/include/asm/efi.h  |  22 -
 arch/x86/mm/fault.c |   9 ++
 arch/x86/platform/efi/quirks.c  | 140 
 drivers/firmware/efi/runtime-wrappers.c |   6 ++
 4 files changed, 176 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 47202b9e1b8e..1285caccdff4 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -90,8 +90,20 @@ struct efi_scratch {
efi_switch_mm(_mm); \
 })
 
+/*
+ * Returns "EFI_ABORTED" if illegal access by firmware caused to exit
+ * firmware context, otherwise returns status returned by firmware.
+ */
 #define arch_efi_call_virt(p, f, args...)  \
-   efi_call((void *)p->f, args)\
+({ \
+   efi_status_t __s;   \
+   \
+   __s = efi_call((void *)p->f, args); \
+   if (exited_fw_ctx)  \
+   __s = EFI_ABORTED;  \
+   \
+   __s;\
+})
 
 #define arch_efi_call_virt_teardown()  \
 ({ \
@@ -124,6 +136,7 @@ extern void __iomem *__efi_init_fixup efi_ioremap(unsigned 
long addr,
 extern u64 xmm_regs_rsp;
 extern u64 core_regs_rsp;
 extern u64 exit_fw_ctx_rip;
+extern bool exited_fw_ctx;
 extern struct efi_scratch efi_scratch;
 extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
 extern int __init efi_memblock_x86_reserve_range(void);
@@ -147,8 +160,15 @@ extern void efi_switch_mm(struct mm_struct *mm);
 
 #ifdef CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES
 extern void __init efi_save_original_memmap(void);
+extern int efi_illegal_accesses_fixup(unsigned long phys_addr,
+ struct pt_regs *regs);
 #else
 static inline void __init efi_save_original_memmap(void) { }
+static inline int efi_illegal_accesses_fixup(unsigned long phys_addr,
+struct pt_regs *regs)
+{
+   return 0;
+}
 #endif /* CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES */
 
 

[PATCH RFC 8/8] x86/efi: Introduce EFI_WARN_ON_ILLEGAL_ACCESSES

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

There may exist some buggy UEFI firmware implementations that access efi
memory regions other than EFI_RUNTIME_SERVICES_ even after
kernel has assumed control of the platform. This violates UEFI
specification.

If selected, this debug option will print a warning message if the UEFI
firmware tries to access any memory regions which it shouldn't. Along
with the warning, the kernel will also try to fixup/recover from the
page fault triggered by firmware so that the machine doesn't hang.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/Kconfig | 17 +
 1 file changed, 17 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f1dbb4ee19d7..9ff11ec65232 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1957,6 +1957,23 @@ config EFI_MIXED
 
   If unsure, say N.
 
+config EFI_WARN_ON_ILLEGAL_ACCESSES
+   bool "Warn about illegal memory accesses by firmware"
+   depends on EFI
+   help
+ Enable this debug feature so that the kernel can detect illegal
+ memory accesses by firmware and issue a warning. Also,
+ 1. If the illegally accessed region is EFI_BOOT_SERVICES_,
+ the kernel fixes it up by mapping the requested region.
+ 2. If the illegally accessed region is any other region (Eg:
+ EFI_CONVENTIONAL_MEMORY or EFI_LOADER_), then kernel
+ exits firmware context and disables EFI Runtime Services, so that
+ it will never again call buggy firmware.
+ Please see the UEFI specification for details on the expectations
+ of memory usage.
+
+ If unsure, say N.
+
 config SECCOMP
def_bool y
prompt "Enable seccomp to safely compute untrusted bytecode"
-- 
2.7.4

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


[PATCH RFC 6/8] x86/efi: Map EFI_BOOT_SERVICES_ regions only when EFI_WARN_ON_ILLEGAL_ACCESSES is disabled

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

Presently, the kernel maps EFI_BOOT_SERVICES_ regions as a
workaround for buggy firmware that accesses them even when they
shouldn't. With EFI_WARN_ON_ILLEGAL_ACCESSES enabled kernel can now
detect and handle such accesses dynamically. Hence, rather than safely
mapping all the EFI_BOOT_SERVICES_ regions, map only
EFI_RUNTIME_SERVICES_ regions and trap all other illegal
accesses.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/platform/efi/efi.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 7d18b7ed5d41..0ddb22a03d88 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -768,9 +768,13 @@ static bool should_map_region(efi_memory_desc_t *md)
/*
 * Map boot services regions as a workaround for buggy
 * firmware that accesses them even when they shouldn't.
+* (only if CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES is disabled)
 *
 * See efi_{reserve,free}_boot_services().
 */
+   if (IS_ENABLED(CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES))
+   return false;
+
if (md->type == EFI_BOOT_SERVICES_CODE ||
md->type == EFI_BOOT_SERVICES_DATA)
return true;
-- 
2.7.4

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


[PATCH RFC 1/8] x86/efi: Remove __init attribute from memory mapping functions

2018-07-21 Thread Sai Praneeth Prakhya
From: Sai Praneeth 

Buggy firmware could illegally access EFI_BOOT_SERVICES_CODE/DATA
regions even after kernel has assumed control of the platform. When
"CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES" is enabled we provide a page fault
handler that could detect/fixup these illegal accesses. The below
modified functions are used by the page fault handler to fixup illegal
accesses to EFI_BOOT_SERVICES_CODE/DATA regions. As the page fault
handler is present during/after kernel boot it doesn't have an __init
attribute but the below functions have it and thus during kernel build,
we observe "WARNING: modpost: Found * section mismatch(es)". To fix this
build warning we remove __init attribute for all these functions.

In order to not keep these functions needlessly when
"CONFIG_EFI_WARN_ON_ILLEGAL_ACCESSES" is not selected, we add a new
__efi_init_fixup attribute whose value changes based on whether the
config option is selected or not.

Signed-off-by: Sai Praneeth Prakhya 
Suggested-by: Matt Fleming 
Based-on-code-from: Ricardo Neri 
Cc: Al Stone 
Cc: Lee Chun-Yi 
Cc: Borislav Petkov 
Cc: Bhupesh Sharma 
Cc: Ard Biesheuvel 
---
 arch/x86/include/asm/efi.h | 11 ++-
 arch/x86/platform/efi/efi.c|  4 ++--
 arch/x86/platform/efi/efi_32.c |  2 +-
 arch/x86/platform/efi/efi_64.c |  9 +
 drivers/firmware/efi/efi.c |  6 +++---
 include/linux/efi.h| 16 ++--
 6 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index cec5fae23eb3..9b70743400f3 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -103,8 +103,9 @@ struct efi_scratch {
preempt_enable();   \
 })
 
-extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size,
-   u32 type, u64 attribute);
+extern void __iomem *__efi_init_fixup efi_ioremap(unsigned long addr,
+ unsigned long size, u32 type,
+ u64 attribute);
 
 #ifdef CONFIG_KASAN
 /*
@@ -126,13 +127,13 @@ extern int __init efi_memblock_x86_reserve_range(void);
 extern pgd_t * __init efi_call_phys_prolog(void);
 extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
 extern void __init efi_print_memmap(void);
-extern void __init efi_memory_uc(u64 addr, unsigned long size);
-extern void __init efi_map_region(efi_memory_desc_t *md);
+extern void __efi_init_fixup efi_memory_uc(u64 addr, unsigned long size);
+extern void __efi_init_fixup efi_map_region(efi_memory_desc_t *md);
 extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
 extern void efi_sync_low_kernel_mappings(void);
 extern int __init efi_alloc_page_tables(void);
 extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned 
num_pages);
-extern void __init old_map_region(efi_memory_desc_t *md);
+extern void __efi_init_fixup old_map_region(efi_memory_desc_t *md);
 extern void __init runtime_code_page_mkexec(void);
 extern void __init efi_runtime_update_mappings(void);
 extern void __init efi_dump_pagetable(void);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 9061babfbc83..439c2c40bf03 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -572,7 +572,7 @@ void __init runtime_code_page_mkexec(void)
}
 }
 
-void __init efi_memory_uc(u64 addr, unsigned long size)
+void __efi_init_fixup efi_memory_uc(u64 addr, unsigned long size)
 {
unsigned long page_shift = 1UL << EFI_PAGE_SHIFT;
u64 npages;
@@ -582,7 +582,7 @@ void __init efi_memory_uc(u64 addr, unsigned long size)
set_memory_uc(addr, npages);
 }
 
-void __init old_map_region(efi_memory_desc_t *md)
+void __efi_init_fixup old_map_region(efi_memory_desc_t *md)
 {
u64 start_pfn, end_pfn, end;
unsigned long size;
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index 324b93328b37..8f31452bd204 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -58,7 +58,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, 
unsigned num_pages)
return 0;
 }
 
-void __init efi_map_region(efi_memory_desc_t *md)
+void __efi_init_fixup efi_map_region(efi_memory_desc_t *md)
 {
old_map_region(md);
 }
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 448267f1c073..a04298312fdd 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -408,7 +408,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, 
unsigned num_pages)
return 0;
 }
 
-static void __init __map_region(efi_memory_desc_t *md, u64 va)
+static void __efi_init_fixup __map_region(efi_memory_desc_t *md, u64 va)
 {
unsigned long flags = _PAGE_RW;
unsigned long pfn;
@@ -426,7 +426,7 @@ static void __init __map_region(efi_memory_desc_t *md, u64 
va)
 

RE: MY NAME IS MRS BELLA YOSTIN MOHAMMAD

2018-07-21 Thread Mrs Bella Yostin Mohammad
Hello Dear.
My Name is Mrs. Bella Yostin Mohammad, I got your contact from a
business directory search and I decided to contact you directly. well
am originally from South Africa, but based in London, i am searching
for a reliable and honest and understanding person to go into
partnership in investing or to guide me in setting up a lucrative
business in the Middle east countries or the Arab countries,UAE or
OMAN and Kuwait, my plan is for my Son to fly to your country to meet
with you for the discussion and process of the investment.

So am only soliciting for your guidance for partnership or to help me
in investing in any lucrative business if you are interested.

My Idea of business is to invest into Tourism business or Medical
business or Real Estates business, this is my plan and i will be happy
if you will help in explaining more of either of this business which
is better for me to invest into in your country.all i want is to
invest into a good business that will bring higher profit.

like i explained above my plan is to send my Son down to meet with you
so both of you will meet face to face and discuss more so we will know
how to go about the process for the investment..

If you are willing to assist you will never regret assisting i and my son.
mean why if you are interested reply back to me with your mobile
number so that you and my son can discuss more in details.
And also for my Son to make his arrangement to fly down to your
country to meet with you over discussing about the investment.
I look forward for your reply.
Thanks with regards
Mrs. Bella Yostin Mohammad
--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html