Patch "x86/efi: Don't allocate memmap through memblock after mm_init()" has been added to the 4.9-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
x86/efi: Don't allocate memmap through memblock after mm_init()
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
x86-efi-don-t-allocate-memmap-through-memblock-after-mm_init.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
20b1e22d01a4b0b11d3a1066e9feb04be38607ecMon Sep 17 00:00:00 2001
From: Nicolai Stange <[email protected]>
Date: Thu, 5 Jan 2017 13:51:29 +0100
Subject: x86/efi: Don't allocate memmap through memblock after mm_init()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From: Nicolai Stange <[email protected]>
commit 20b1e22d01a4b0b11d3a1066e9feb04be38607ec upstream.
With the following commit:
4bc9f92e64c8 ("x86/efi-bgrt: Use efi_mem_reserve() to avoid copying image data")
... efi_bgrt_init() calls into the memblock allocator through efi_mem_reserve() => efi_arch_mem_reserve() *after* mm_init() has been called.
Indeed, KASAN reports a bad read access later on in efi_free_boot_services():
BUG: KASAN: use-after-free in efi_free_boot_services+0xae/0x24c
at addr ffff88022de12740
Read of size 4 by task swapper/0/0
page:ffffea0008b78480 count:0 mapcount:-127
mapping: (null) index:0x1 flags: 0x5fff8000000000()
[...]
Call Trace:
dump_stack+0x68/0x9f
kasan_report_error+0x4c8/0x500
kasan_report+0x58/0x60
__asan_load4+0x61/0x80
efi_free_boot_services+0xae/0x24c
start_kernel+0x527/0x562
x86_64_start_reservations+0x24/0x26
x86_64_start_kernel+0x157/0x17a
start_cpu+0x5/0x14The instruction at the given address is the first read from the memmap's memory, i.e. the read of md->type in efi_free_boot_services().
Note that the writes earlier in efi_arch_mem_reserve() don't splat because they're done through early_memremap()ed addresses.
So, after memblock is gone, allocations should be done through the "normal" page allocator. Introduce a helper, efi_memmap_alloc() for this. Use it from efi_arch_mem_reserve(), efi_free_boot_services() and, for the sake of consistency, from efi_fake_memmap() as well.
Note that for the latter, the memmap allocations cease to be page aligned. This isn't needed though.
--- arch/x86/platform/efi/quirks.c | 4 ++-- drivers/firmware/efi/fake_mem.c | 3 +-- drivers/firmware/efi/memmap.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/efi.h | 1 + 4 files changed, 42 insertions(+), 4 deletions(-)
arch/x86/platform/efi/quirks.c +2 -2
@@ -214,7 +214,7 @@ void __init efi_arch_mem_reserve(phys_ad new_size = efi.memmap.desc_size * num_entries; - new_phys =memblock_alloc (new_size,0 ); + new_phys =efi_memmap_alloc (num_entries);if (!new_phys) {pr_err ("Could not allocate boot services memmap\n" );return ;
@@ -355,7 +355,7 @@ void __init efi_free_boot_services(void) } new_size = efi.memmap.desc_size * num_entries; - new_phys =memblock_alloc (new_size,0 ); + new_phys =efi_memmap_alloc (num_entries);if (!new_phys) {pr_err ("Failed to allocate new EFI memmap\n" );return ;
drivers/firmware/efi/fake_mem.c +1 -2
@@ -71,8 +71,7 @@ void __init efi_fake_memmap(void) }/* allocate memory for new EFI memmap */ - new_memmap_phy =memblock_alloc (efi.memmap.desc_size * new_nr_map, -PAGE_SIZE ); + new_memmap_phy =efi_memmap_alloc (new_nr_map);if (!new_memmap_phy)return ;
drivers/firmware/efi/memmap.c +38 -0
@@ -9,6 +9,44 @@#include <linux/efi.h> #include <linux/io.h> #include <asm/early_ioremap.h> +#include <linux/memblock.h> +#include <linux/slab.h> + +static phys_addr_t __init __efi_memmap_alloc_early (unsigned long size) +{ +return memblock_alloc (size,0 ); +} + +static phys_addr_t __init __efi_memmap_alloc_late (unsigned long size) +{ +unsigned int order =get_order (size); +struct page *p =alloc_pages (GFP_KERNEL , order); + +if (!p) +return 0 ; + +return PFN_PHYS (page_to_pfn (p)); +} + +/** +* efi_memmap_alloc - Allocate memory for the EFI memory map +* @num_entries: Number of entries in the allocated map. +* +* Depending on whether mm_init() has already been invoked or not, +* either memblock or "normal" page allocation is used. +* +* Returns the physical address of the allocated memory map on +* success, zero on failure. +*/ +phys_addr_t __init efi_memmap_alloc (unsigned int num_entries) +{ +unsigned long size = num_entries * efi.memmap.desc_size; + +if (slab_is_available ()) +return __efi_memmap_alloc_late (size); + +return __efi_memmap_alloc_early (size); +}/** * __efi_memmap_init - Common code for mapping the EFI memory map
include/linux/efi.h +1 -0
@@ -931,6 +931,7 @@ static inline efi_status_t efi_query_var#endif extern void __iomem *efi_lookup_mapped_addr (u64 phys_addr); +extern phys_addr_t __init efi_memmap_alloc (unsigned int num_entries);extern int __init efi_memmap_init_early (struct efi_memory_map_data *data);extern int __init efi_memmap_init_late (phys_addr_t addr,unsigned long size);extern void __init efi_memmap_unmap (void );
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/x86-efi-don-t-allocate-memmap-through-memblock-after-mm_init.patch