From 9e46e4dcd9d6cd88342b028dbfa5f4fb7483d39c Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Wed, 19 Jul 2023 15:41:37 -0400 Subject: mm,memblock: reset memblock.reserved to system init state to prevent UAF The memblock_discard function frees the memblock.reserved.regions array, which is good. However, if a subsequent memblock_free (or memblock_phys_free) comes in later, from for example ima_free_kexec_buffer, that will result in a use after free bug in memblock_isolate_range. When running a kernel with CONFIG_KASAN enabled, this will cause a kernel panic very early in boot. Without CONFIG_KASAN, there is a chance that memblock_isolate_range might scribble on memory that is now in use by somebody else. Avoid those issues by making sure that memblock_discard points memblock.reserved.regions back at the static buffer. If memblock_free is called after memblock memory is discarded, that will print a warning in memblock_remove_region. Signed-off-by: Rik van Riel Link: https://lore.kernel.org/r/20230719154137.732d8525@imladris.surriel.com Signed-off-by: Mike Rapoport (IBM) --- mm/memblock.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mm/memblock.c') diff --git a/mm/memblock.c b/mm/memblock.c index f9e61e565a53..c39b36378f5d 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -374,6 +374,10 @@ void __init memblock_discard(void) kfree(memblock.reserved.regions); else memblock_free_late(addr, size); + /* Reset to prevent UAF from stray frees. */ + memblock.reserved.regions = memblock_reserved_init_regions; + memblock.reserved.cnt = 1; + memblock_remove_region(&memblock.reserved, 0); } if (memblock.memory.regions != memblock_memory_init_regions) { -- cgit v1.2.3 From c442a957b2f4e116f28aeb55bf2719cb7bb2ad60 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (IBM)" Date: Fri, 28 Jul 2023 13:55:12 +0300 Subject: Revert "mm,memblock: reset memblock.reserved to system init state to prevent UAF" This reverts commit 9e46e4dcd9d6cd88342b028dbfa5f4fb7483d39c. kbuild reports a warning in memblock_remove_region() because of a false positive caused by partial reset of the memblock state. Doing the full reset will remove the false positives, but will allow late use of memblock_free() to go unnoticed, so it is better to revert the offending commit. WARNING: CPU: 0 PID: 1 at mm/memblock.c:352 memblock_remove_region (kbuild/src/x86_64/mm/memblock.c:352 (discriminator 1)) Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.5.0-rc3-00001-g9e46e4dcd9d6 #2 RIP: 0010:memblock_remove_region (kbuild/src/x86_64/mm/memblock.c:352 (discriminator 1)) Call Trace: memblock_discard (kbuild/src/x86_64/mm/memblock.c:383) page_alloc_init_late (kbuild/src/x86_64/include/linux/find.h:208 kbuild/src/x86_64/include/linux/nodemask.h:266 kbuild/src/x86_64/mm/mm_init.c:2405) kernel_init_freeable (kbuild/src/x86_64/init/main.c:1325 kbuild/src/x86_64/init/main.c:1546) kernel_init (kbuild/src/x86_64/init/main.c:1439) ret_from_fork (kbuild/src/x86_64/arch/x86/kernel/process.c:145) ret_from_fork_asm (kbuild/src/x86_64/arch/x86/entry/entry_64.S:298) Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202307271656.447aa17e-oliver.sang@intel.com Signed-off-by: "Mike Rapoport (IBM)" Signed-off-by: Linus Torvalds --- mm/memblock.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'mm/memblock.c') diff --git a/mm/memblock.c b/mm/memblock.c index c39b36378f5d..f9e61e565a53 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -374,10 +374,6 @@ void __init memblock_discard(void) kfree(memblock.reserved.regions); else memblock_free_late(addr, size); - /* Reset to prevent UAF from stray frees. */ - memblock.reserved.regions = memblock_reserved_init_regions; - memblock.reserved.cnt = 1; - memblock_remove_region(&memblock.reserved, 0); } if (memblock.memory.regions != memblock_memory_init_regions) { -- cgit v1.2.3 From 0db31d63f27e5b8ca84b9fd5a3cff5b12ac88abf Mon Sep 17 00:00:00 2001 From: Ma Wupeng Date: Wed, 2 Aug 2023 15:23:28 +0800 Subject: mm: disable kernelcore=mirror when no mirror memory For system with kernelcore=mirror enabled while no mirrored memory is reported by efi. This could lead to kernel OOM during startup since all memory beside zone DMA are in the movable zone and this prevents the kernel to use it. Zone DMA/DMA32 initialization is independent of mirrored memory and their max pfn is set in zone_sizes_init(). Since kernel can fallback to zone DMA/DMA32 if there is no memory in zone Normal, these zones are seen as mirrored memory no mather their memory attributes are. To solve this problem, disable kernelcore=mirror when there is no real mirrored memory exists. Link: https://lkml.kernel.org/r/20230802072328.2107981-1-mawupeng1@huawei.com Signed-off-by: Ma Wupeng Suggested-by: Kefeng Wang Suggested-by: Mike Rapoport Reviewed-by: Mike Rapoport (IBM) Reviewed-by: Kefeng Wang Cc: Levi Yun Signed-off-by: Andrew Morton --- mm/internal.h | 1 + mm/memblock.c | 5 +++++ mm/mm_init.c | 5 +++++ 3 files changed, 11 insertions(+) (limited to 'mm/memblock.c') diff --git a/mm/internal.h b/mm/internal.h index 5a03bc4782a2..a037b1b37f6d 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -1022,6 +1022,7 @@ static inline bool gup_must_unshare(struct vm_area_struct *vma, } extern bool mirrored_kernelcore; +extern bool memblock_has_mirror(void); static inline bool vma_soft_dirty_enabled(struct vm_area_struct *vma) { diff --git a/mm/memblock.c b/mm/memblock.c index f9e61e565a53..913b2520a9a0 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -161,6 +161,11 @@ static int memblock_can_resize __initdata_memblock; static int memblock_memory_in_slab __initdata_memblock; static int memblock_reserved_in_slab __initdata_memblock; +bool __init_memblock memblock_has_mirror(void) +{ + return system_has_some_mirror; +} + static enum memblock_flags __init_memblock choose_memblock_flags(void) { return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE; diff --git a/mm/mm_init.c b/mm/mm_init.c index a2fbaa8d917f..2a19f3151661 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -376,6 +376,11 @@ static void __init find_zone_movable_pfns_for_nodes(void) if (mirrored_kernelcore) { bool mem_below_4gb_not_mirrored = false; + if (!memblock_has_mirror()) { + pr_warn("The system has no mirror memory, ignore kernelcore=mirror.\n"); + goto out; + } + for_each_mem_region(r) { if (memblock_is_mirror(r)) continue; -- cgit v1.2.3