From 88d259a75c05e46ce19dd31cf037627d6fb572d4 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 20 Feb 2016 23:24:53 +0000 Subject: [PATCH] [x86] efi-bgrt: Fix kernel panic when mapping BGRT data (Closes: #815125) Plus the following fix-up. --- debian/changelog | 7 + ...-kernel-panic-when-mapping-bgrt-data.patch | 180 ++++++++++++++++++ ...replace-early_memremap-with-memremap.patch | 92 +++++++++ debian/patches/series | 2 + 4 files changed, 281 insertions(+) create mode 100644 debian/patches/bugfix/x86/x86-efi-bgrt-fix-kernel-panic-when-mapping-bgrt-data.patch create mode 100644 debian/patches/bugfix/x86/x86-efi-bgrt-replace-early_memremap-with-memremap.patch diff --git a/debian/changelog b/debian/changelog index 9628e6f97..79499b603 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +linux (4.4.2-3) UNRELEASED; urgency=medium + + * [x86] efi-bgrt: Fix kernel panic when mapping BGRT data (Closes: #815125) + * [x86] efi-bgrt: Replace early_memremap() with memremap() + + -- Ben Hutchings Sat, 20 Feb 2016 23:24:00 +0000 + linux (4.4.2-2) unstable; urgency=medium [ Ben Hutchings ] diff --git a/debian/patches/bugfix/x86/x86-efi-bgrt-fix-kernel-panic-when-mapping-bgrt-data.patch b/debian/patches/bugfix/x86/x86-efi-bgrt-fix-kernel-panic-when-mapping-bgrt-data.patch new file mode 100644 index 000000000..bcba95b03 --- /dev/null +++ b/debian/patches/bugfix/x86/x86-efi-bgrt-fix-kernel-panic-when-mapping-bgrt-data.patch @@ -0,0 +1,180 @@ +From: Sai Praneeth +Date: Wed, 9 Dec 2015 15:41:08 -0800 +Subject: x86/efi-bgrt: Fix kernel panic when mapping BGRT data +Origin: https://git.kernel.org/cgit/linux/kernel/git/mfleming/efi.git/commit?id=50a0cb565246f20d59cdb161778531e4b19d35ac +Bug-Debian: https://bugs.debian.org/815125 + +Starting with this commit 35eb8b81edd4 ("x86/efi: Build our own page +table structures") efi regions have a separate page directory called +"efi_pgd". In order to access any efi region we have to first shift %cr3 +to this page table. In the bgrt code we are trying to copy bgrt_header +and image, but these regions fall under "EFI_BOOT_SERVICES_DATA" +and to access these regions we have to shift %cr3 to efi_pgd and not +doing so will cause page fault as shown below. + +[ 0.251599] Last level dTLB entries: 4KB 64, 2MB 0, 4MB 0, 1GB 4 +[ 0.259126] Freeing SMP alternatives memory: 32K (ffffffff8230e000 - ffffffff82316000) +[ 0.271803] BUG: unable to handle kernel paging request at fffffffefce35002 +[ 0.279740] IP: [] efi_bgrt_init+0x144/0x1fd +[ 0.286383] PGD 300f067 PUD 0 +[ 0.289879] Oops: 0000 [#1] SMP +[ 0.293566] Modules linked in: +[ 0.297039] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.0-rc1-eywa-eywa-built-in-47041+ #2 +[ 0.306619] Hardware name: Intel Corporation Skylake Client platform/Skylake Y LPDDR3 RVP3, BIOS SKLSE2R1.R00.B104.B01.1511110114 11/11/2015 +[ 0.320925] task: ffffffff820134c0 ti: ffffffff82000000 task.ti: ffffffff82000000 +[ 0.329420] RIP: 0010:[] [] efi_bgrt_init+0x144/0x1fd +[ 0.338821] RSP: 0000:ffffffff82003f18 EFLAGS: 00010246 +[ 0.344852] RAX: fffffffefce35000 RBX: fffffffefce35000 RCX: fffffffefce2b000 +[ 0.352952] RDX: 000000008a82b000 RSI: ffffffff8235bb80 RDI: 000000008a835000 +[ 0.361050] RBP: ffffffff82003f30 R08: 000000008a865000 R09: ffffffffff202850 +[ 0.369149] R10: ffffffff811ad62f R11: 0000000000000000 R12: 0000000000000000 +[ 0.377248] R13: ffff88016dbaea40 R14: ffffffff822622c0 R15: ffffffff82003fb0 +[ 0.385348] FS: 0000000000000000(0000) GS:ffff88016d800000(0000) knlGS:0000000000000000 +[ 0.394533] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 0.401054] CR2: fffffffefce35002 CR3: 000000000300c000 CR4: 00000000003406f0 +[ 0.409153] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[ 0.417252] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[ 0.425350] Stack: +[ 0.427638] ffffffffffffffff ffffffff82256900 ffff88016dbaea40 ffffffff82003f40 +[ 0.436086] ffffffff821bbce0 ffffffff82003f88 ffffffff8219c0c2 0000000000000000 +[ 0.444533] ffffffff8219ba4a ffffffff822622c0 0000000000083000 00000000ffffffff +[ 0.452978] Call Trace: +[ 0.455763] [] efi_late_init+0x9/0xb +[ 0.461697] [] start_kernel+0x463/0x47f +[ 0.467928] [] ? set_init_arg+0x55/0x55 +[ 0.474159] [] ? early_idt_handler_array+0x120/0x120 +[ 0.481669] [] x86_64_start_reservations+0x2a/0x2c +[ 0.488982] [] x86_64_start_kernel+0x13d/0x14c +[ 0.495897] Code: 00 41 b4 01 48 8b 78 28 e8 09 36 01 00 48 85 c0 48 89 c3 75 13 48 c7 c7 f8 ac d3 81 31 c0 e8 d7 3b fb fe e9 b5 00 00 00 45 84 e4 <44> 8b 6b 02 74 0d be 06 00 00 00 48 89 df e8 ae 34 0$ +[ 0.518151] RIP [] efi_bgrt_init+0x144/0x1fd +[ 0.524888] RSP +[ 0.528851] CR2: fffffffefce35002 +[ 0.532615] ---[ end trace 7b06521e6ebf2aea ]--- +[ 0.537852] Kernel panic - not syncing: Attempted to kill the idle task! + +As said above one way to fix this bug is to shift %cr3 to efi_pgd but we +are not doing that way because it leaks inner details of how we switch +to EFI page tables into a new call site and it also adds duplicate code. +Instead, we remove the call to efi_lookup_mapped_addr() and always +perform early_mem*() instead of early_io*() because we want to remap RAM +regions and not I/O regions. We also delete efi_lookup_mapped_addr() +because we are no longer using it. + +Signed-off-by: Sai Praneeth Prakhya +Reported-by: Wendy Wang +Cc: Borislav Petkov +Cc: Josh Triplett +Cc: Ricardo Neri +Cc: Ravi Shankar +Signed-off-by: Matt Fleming +--- + arch/x86/platform/efi/efi-bgrt.c | 39 ++++++++++++++------------------------- + drivers/firmware/efi/efi.c | 32 -------------------------------- + 2 files changed, 14 insertions(+), 57 deletions(-) + +--- a/arch/x86/platform/efi/efi-bgrt.c ++++ b/arch/x86/platform/efi/efi-bgrt.c +@@ -28,8 +28,7 @@ struct bmp_header { + void __init efi_bgrt_init(void) + { + acpi_status status; +- void __iomem *image; +- bool ioremapped = false; ++ void *image; + struct bmp_header bmp_header; + + if (acpi_disabled) +@@ -70,20 +69,14 @@ void __init efi_bgrt_init(void) + return; + } + +- image = efi_lookup_mapped_addr(bgrt_tab->image_address); ++ image = early_memremap(bgrt_tab->image_address, sizeof(bmp_header)); + if (!image) { +- image = early_ioremap(bgrt_tab->image_address, +- sizeof(bmp_header)); +- ioremapped = true; +- if (!image) { +- pr_err("Ignoring BGRT: failed to map image header memory\n"); +- return; +- } ++ pr_err("Ignoring BGRT: failed to map image header memory\n"); ++ return; + } + +- memcpy_fromio(&bmp_header, image, sizeof(bmp_header)); +- if (ioremapped) +- early_iounmap(image, sizeof(bmp_header)); ++ memcpy(&bmp_header, image, sizeof(bmp_header)); ++ early_memunmap(image, sizeof(bmp_header)); + bgrt_image_size = bmp_header.size; + + bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN); +@@ -93,18 +86,14 @@ void __init efi_bgrt_init(void) + return; + } + +- if (ioremapped) { +- image = early_ioremap(bgrt_tab->image_address, +- bmp_header.size); +- if (!image) { +- pr_err("Ignoring BGRT: failed to map image memory\n"); +- kfree(bgrt_image); +- bgrt_image = NULL; +- return; +- } ++ image = early_memremap(bgrt_tab->image_address, bmp_header.size); ++ if (!image) { ++ pr_err("Ignoring BGRT: failed to map image memory\n"); ++ kfree(bgrt_image); ++ bgrt_image = NULL; ++ return; + } + +- memcpy_fromio(bgrt_image, image, bgrt_image_size); +- if (ioremapped) +- early_iounmap(image, bmp_header.size); ++ memcpy(bgrt_image, image, bgrt_image_size); ++ early_memunmap(image, bmp_header.size); + } +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -324,38 +324,6 @@ u64 __init efi_mem_desc_end(efi_memory_d + return end; + } + +-/* +- * We can't ioremap data in EFI boot services RAM, because we've already mapped +- * it as RAM. So, look it up in the existing EFI memory map instead. Only +- * callable after efi_enter_virtual_mode and before efi_free_boot_services. +- */ +-void __iomem *efi_lookup_mapped_addr(u64 phys_addr) +-{ +- struct efi_memory_map *map; +- void *p; +- map = efi.memmap; +- if (!map) +- return NULL; +- if (WARN_ON(!map->map)) +- return NULL; +- for (p = map->map; p < map->map_end; p += map->desc_size) { +- efi_memory_desc_t *md = p; +- u64 size = md->num_pages << EFI_PAGE_SHIFT; +- u64 end = md->phys_addr + size; +- if (!(md->attribute & EFI_MEMORY_RUNTIME) && +- md->type != EFI_BOOT_SERVICES_CODE && +- md->type != EFI_BOOT_SERVICES_DATA) +- continue; +- if (!md->virt_addr) +- continue; +- if (phys_addr >= md->phys_addr && phys_addr < end) { +- phys_addr += md->virt_addr - md->phys_addr; +- return (__force void __iomem *)(unsigned long)phys_addr; +- } +- } +- return NULL; +-} +- + static __initdata efi_config_table_type_t common_tables[] = { + {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, + {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, diff --git a/debian/patches/bugfix/x86/x86-efi-bgrt-replace-early_memremap-with-memremap.patch b/debian/patches/bugfix/x86/x86-efi-bgrt-replace-early_memremap-with-memremap.patch new file mode 100644 index 000000000..e695fd9ee --- /dev/null +++ b/debian/patches/bugfix/x86/x86-efi-bgrt-replace-early_memremap-with-memremap.patch @@ -0,0 +1,92 @@ +From: Matt Fleming +Date: Mon, 21 Dec 2015 14:12:52 +0000 +Subject: x86/efi-bgrt: Replace early_memremap() with memremap() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/cgit/linux/kernel/git/mfleming/efi.git/commit?id=e2c90dd7e11e3025b46719a79fb4bb1e7a5cef9f +Bug-Debian: https://bugs.debian.org/815125 + +Môshe reported the following warning triggered on his machine since +commit 50a0cb565246 ("x86/efi-bgrt: Fix kernel panic when mapping BGRT +data"), + + [ 0.026936] ------------[ cut here ]------------ + [ 0.026941] WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:137 __early_ioremap+0x102/0x1bb() + [ 0.026941] Modules linked in: + [ 0.026944] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.0-rc1 #2 + [ 0.026945] Hardware name: Dell Inc. XPS 13 9343/09K8G1, BIOS A05 07/14/2015 + [ 0.026946] 0000000000000000 900f03d5a116524d ffffffff81c03e60 ffffffff813a3fff + [ 0.026948] 0000000000000000 ffffffff81c03e98 ffffffff810a0852 00000000d7b76000 + [ 0.026949] 0000000000000000 0000000000000001 0000000000000001 000000000000017c + [ 0.026951] Call Trace: + [ 0.026955] [] dump_stack+0x44/0x55 + [ 0.026958] [] warn_slowpath_common+0x82/0xc0 + [ 0.026959] [] warn_slowpath_null+0x1a/0x20 + [ 0.026961] [] __early_ioremap+0x102/0x1bb + [ 0.026962] [] early_memremap+0x13/0x15 + [ 0.026964] [] efi_bgrt_init+0x162/0x1ad + [ 0.026966] [] efi_late_init+0x9/0xb + [ 0.026968] [] start_kernel+0x46f/0x49f + [ 0.026970] [] ? early_idt_handler_array+0x120/0x120 + [ 0.026972] [] x86_64_start_reservations+0x2a/0x2c + [ 0.026974] [] x86_64_start_kernel+0x14a/0x16d + [ 0.026977] ---[ end trace f9b3812eb8e24c58 ]--- + [ 0.026978] efi_bgrt: Ignoring BGRT: failed to map image memory + +early_memremap() has an upper limit on the size of mapping it can +handle which is ~200KB. Clearly the BGRT image on Môshe's machine is +much larger than that. + +There's actually no reason to restrict ourselves to using the early_* +version of memremap() - the ACPI BGRT driver is invoked late enough in +boot that we can use the standard version, with the benefit that the +late version allows mappings of arbitrary size. + +Reported-by: Môshe van der Sterre +Tested-by: Môshe van der Sterre +Signed-off-by: Matt Fleming +Cc: Josh Triplett +Cc: Sai Praneeth Prakhya +Cc: Borislav Petkov +Link: http://lkml.kernel.org/r/1450707172-12561-1-git-send-email-matt@codeblueprint.co.uk +Signed-off-by: Thomas Gleixner +--- + arch/x86/platform/efi/efi-bgrt.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/x86/platform/efi/efi-bgrt.c ++++ b/arch/x86/platform/efi/efi-bgrt.c +@@ -69,14 +69,14 @@ void __init efi_bgrt_init(void) + return; + } + +- image = early_memremap(bgrt_tab->image_address, sizeof(bmp_header)); ++ image = memremap(bgrt_tab->image_address, sizeof(bmp_header), MEMREMAP_WB); + if (!image) { + pr_err("Ignoring BGRT: failed to map image header memory\n"); + return; + } + + memcpy(&bmp_header, image, sizeof(bmp_header)); +- early_memunmap(image, sizeof(bmp_header)); ++ memunmap(image); + bgrt_image_size = bmp_header.size; + + bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN); +@@ -86,7 +86,7 @@ void __init efi_bgrt_init(void) + return; + } + +- image = early_memremap(bgrt_tab->image_address, bmp_header.size); ++ image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB); + if (!image) { + pr_err("Ignoring BGRT: failed to map image memory\n"); + kfree(bgrt_image); +@@ -95,5 +95,5 @@ void __init efi_bgrt_init(void) + } + + memcpy(bgrt_image, image, bgrt_image_size); +- early_memunmap(image, bmp_header.size); ++ memunmap(image); + } diff --git a/debian/patches/series b/debian/patches/series index ec1bad367..971ac10d5 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -130,3 +130,5 @@ bugfix/x86/x86-mm-fix-types-used-in-pgprot-cacheability-flags-t.patch debian/i386-686-pae-pci-set-pci-nobios-by-default.patch bugfix/all/iff_no_queue-fix-for-drivers-not-calling-ether_setup.patch bugfix/arm/net-mv643xx_eth-fix-packet-corruption-with-tso-and-t.patch +bugfix/x86/x86-efi-bgrt-fix-kernel-panic-when-mapping-bgrt-data.patch +bugfix/x86/x86-efi-bgrt-replace-early_memremap-with-memremap.patch