Skip to content

Commit 5d0faa8

Browse files
committed
efi/memattr: Fix thinko in table size sanity check
While it is true that each PE/COFF runtime driver in memory can generally be split into 3 different regions (the header, the code/rodata region and the data/bss region), each with different permissions, it does not mean that 3x the size of the memory map is a suitable upper bound. This is due to the fact that all runtime drivers could be coalesced into a single EFI runtime code region by the firmware, and if the firmware does a good job of keeping the fragmentation down, it is conceivable that the memory attributes table has more entries than the EFI memory map itself. So instead, base the sanity check on whether the descriptor size matches the EFI memory map's descriptor size closely enough (which is not mandated by the spec but extremely unlikely to differ in practice), and whether the size of the whole table does not exceed 64k entries. Reviewed-by: Breno Leitao <leitao@debian.org> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 56e2ef8 commit 5d0faa8

1 file changed

Lines changed: 28 additions & 9 deletions

File tree

drivers/firmware/efi/memattr.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ unsigned long __ro_after_init efi_mem_attr_table = EFI_INVALID_TABLE_ADDR;
2222
void __init efi_memattr_init(void)
2323
{
2424
efi_memory_attributes_table_t *tbl;
25-
unsigned long size;
2625

2726
if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR)
2827
return;
@@ -40,22 +39,42 @@ void __init efi_memattr_init(void)
4039
goto unmap;
4140
}
4241

42+
/*
43+
* The EFI memory attributes table descriptors might potentially be
44+
* smaller than those used by the EFI memory map, as long as they can
45+
* fit a efi_memory_desc_t. However, a larger descriptor size makes no
46+
* sense, and might be an indication that the table is corrupted.
47+
*
48+
* The only exception is kexec_load(), where the EFI memory map is
49+
* reconstructed by user space, and may use a smaller descriptor size
50+
* than the original. Given that, ignoring this companion table is
51+
* still the right thing to do here, but don't complain too loudly when
52+
* this happens.
53+
*/
54+
if (tbl->desc_size < sizeof(efi_memory_desc_t) ||
55+
tbl->desc_size > efi.memmap.desc_size) {
56+
pr_warn("Unexpected EFI Memory Attributes descriptor size %u (expected: %lu)\n",
57+
tbl->desc_size, efi.memmap.desc_size);
58+
goto unmap;
59+
}
4360

4461
/*
45-
* Sanity check: the Memory Attributes Table contains up to 3 entries
46-
* for each entry of type EfiRuntimeServicesCode in the EFI memory map.
47-
* So if the size of the table exceeds 3x the size of the entire EFI
48-
* memory map, there is clearly something wrong, and the table should
49-
* just be ignored altogether.
62+
* Sanity check: the Memory Attributes Table contains multiple entries
63+
* for each EFI runtime services code or data region in the EFI memory
64+
* map, each with the permission attributes that may be applied when
65+
* mapping the region. There is no upper bound for the number of
66+
* entries, as it could conceivably contain more entries than the EFI
67+
* memory map itself. So pick an arbitrary limit of 64k, which is
68+
* ludicrously high. This prevents a corrupted table from eating all
69+
* system RAM.
5070
*/
51-
size = tbl->num_entries * tbl->desc_size;
52-
if (size > 3 * efi.memmap.nr_map * efi.memmap.desc_size) {
71+
if (tbl->num_entries > SZ_64K) {
5372
pr_warn(FW_BUG "Corrupted EFI Memory Attributes Table detected! (version == %u, desc_size == %u, num_entries == %u)\n",
5473
tbl->version, tbl->desc_size, tbl->num_entries);
5574
goto unmap;
5675
}
5776

58-
tbl_size = sizeof(*tbl) + size;
77+
tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size;
5978
memblock_reserve(efi_mem_attr_table, tbl_size);
6079
set_bit(EFI_MEM_ATTR, &efi.flags);
6180

0 commit comments

Comments
 (0)