]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
kern/efi/mm: Change grub_efi_mm_add_regions() to keep track of map allocation size
authorMate Kukri <mate.kukri@canonical.com>
Wed, 12 Jun 2024 15:10:49 +0000 (16:10 +0100)
committerDaniel Kiper <daniel.kiper@oracle.com>
Thu, 20 Jun 2024 13:30:32 +0000 (15:30 +0200)
If the map was too big for the initial allocation, it was freed and replaced
with a bigger one, but the free call still used the hard-coded size.

Seems like this wasn't hit for a long time, because most firmware maps
fit into 12K.

This bug was triggered on Project Mu firmware with a big memory map, and
results in the heap getting trashed and the firmware ASSERTING on
corrupted heap guard values when GRUB exits.

Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/kern/efi/mm.c

index 6a6fba891846d6ea8ecd89e456ee9ad3613f7fc0..739229e7b53bbcbae5c36b5438739a7c0e67767b 100644 (file)
@@ -574,13 +574,15 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
   grub_efi_memory_descriptor_t *memory_map_end;
   grub_efi_memory_descriptor_t *filtered_memory_map;
   grub_efi_memory_descriptor_t *filtered_memory_map_end;
+  grub_efi_uintn_t alloc_size;
   grub_efi_uintn_t map_size;
   grub_efi_uintn_t desc_size;
   grub_err_t err;
   int mm_status;
 
   /* Prepare a memory region to store two memory maps.  */
-  memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+  alloc_size = 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE);
+  memory_map = grub_efi_allocate_any_pages (alloc_size);
   if (! memory_map)
     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");
 
@@ -591,14 +593,13 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
 
   if (mm_status == 0)
     {
-      grub_efi_free_pages
-       ((grub_efi_physical_address_t) ((grub_addr_t) memory_map),
-        2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+      grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) memory_map, alloc_size);
 
       /* Freeing/allocating operations may increase memory map size.  */
       map_size += desc_size * 32;
 
-      memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
+      alloc_size = 2 * BYTES_TO_PAGES (map_size);
+      memory_map = grub_efi_allocate_any_pages (alloc_size);
       if (! memory_map)
        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");
 
@@ -642,8 +643,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
 #endif
 
   /* Release the memory maps.  */
-  grub_efi_free_pages ((grub_addr_t) memory_map,
-                      2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+  grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) memory_map, alloc_size);
 
   return GRUB_ERR_NONE;
 }