From: Masayoshi Mizuma <[email protected]>

The system sometimes crashes while memory hot-adding on KASLR
enabled system. The crash happens because the regions pointed by
kaslr_regions[].base are overwritten by the hot-added memory.

It happens because of the padding size for kaslr_regions[].base isn't
enough for the system whose physical memory layout has huge space for
memory hotplug. kaslr_regions[].base points "actual installed
memory size + padding" or higher address. So, if the "actual + padding"
is lower address than the maximum memory address, which means the memory
address reachable by memory hot-add, kaslr_regions[].base is destroyed by
the overwritten.

  address
    ^
    |------- maximum memory address (Hotplug)
    |                                    ^
    |------- kaslr_regions[0].base       | Hotadd-able region
    |     ^                              |
    |     | padding                      |
    |     V                              V
    |------- actual memory address (Installed on boot)
    |

Fix it by getting the maximum memory address from SRAT and store
the value in boot_param, then set the padding size while KASLR
initializing if the default padding size isn't enough.

Signed-off-by: Masayoshi Mizuma <[email protected]>
---
 arch/x86/mm/kaslr.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c
index 8e5f3642e..a78844c57 100644
--- a/arch/x86/mm/kaslr.c
+++ b/arch/x86/mm/kaslr.c
@@ -70,6 +70,34 @@ static inline bool kaslr_memory_enabled(void)
        return kaslr_enabled() && !IS_ENABLED(CONFIG_KASAN);
 }
 
+static inline unsigned long phys_memmap_size(void)
+{
+       unsigned long padding = CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING;
+#ifdef CONFIG_MEMORY_HOTPLUG
+       unsigned long actual, maximum, base;
+
+       if (!boot_params.max_addr)
+               goto out;
+
+       /*
+        * The padding size should set to get for kaslr_regions[].base
+        * bigger address than the maximum memory address the system can
+        * have. kaslr_regions[].base points "actual size + padding" or
+        * higher address. If "actual size + padding" points the lower
+        * address than the maximum memory size, fix the padding size.
+        */
+       actual = roundup(PFN_PHYS(max_pfn), 1UL << TB_SHIFT);
+       maximum = roundup(boot_params.max_addr, 1UL << TB_SHIFT);
+       base = actual + (padding << TB_SHIFT);
+
+       if (maximum > base)
+               padding = (maximum - actual) >> TB_SHIFT;
+out:
+#endif
+       return DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) +
+                       padding;
+}
+
 /*
  * Even though a huge virtual address space is reserved for the direct
  * mapping of physical memory, e.g in 4-level paging mode, it's 64TB,
@@ -87,8 +115,7 @@ static inline unsigned long calc_direct_mapping_size(void)
         * Update Physical memory mapping to available and
         * add padding if needed (especially for memory hotplug support).
         */
-       memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) +
-               CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING;
+       memory_tb = phys_memmap_size();
 
        size_tb = 1 << (MAX_PHYSMEM_BITS - TB_SHIFT);
 
-- 
2.18.1

Reply via email to