Skip to content

Commit f9d230e

Browse files
committed
x86/boot: Correct RSDP parsing with 32-bit EFI
Guenter Roeck reported triple faults of a 64-bit VM using a 32-bit OVMF EFI image. After some singlestepping of the image in gdb, it turned out that some of the EFI config tables were at bogus addresses. Which, as Ard pointed out, results from using the wrong efi_config_table typedef. So switch all EFI table pointers to unsigned longs and convert them to the proper typedef only when accessing them. This way, the proper table type is being used. Shorten variable names, while at it. Fixes: 33f0df8 ("x86/boot: Search for RSDP in the EFI tables") Reported-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Borislav Petkov <bp@suse.de> Tested-by: Chao Fan <fanc.fnst@cn.fujitsu.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: bhe@redhat.com Cc: caoj.fnst@cn.fujitsu.com Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: indou.takao@jp.fujitsu.com Cc: Ingo Molnar <mingo@redhat.com> Cc: kasong@redhat.com Cc: Kees Cook <keescook@chromium.org> Cc: msys.mizuma@gmail.com Cc: Thomas Gleixner <tglx@linutronix.de> Cc: x86-ml <x86@kernel.org> Link: https://lkml.kernel.org/r/20190208190248.GA10854@roeck-us.net
1 parent ccec81e commit f9d230e

File tree

1 file changed

+31
-19
lines changed
  • arch/x86/boot/compressed

1 file changed

+31
-19
lines changed

arch/x86/boot/compressed/acpi.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ static acpi_physical_address efi_get_rsdp_addr(void)
5050
acpi_physical_address rsdp_addr = 0;
5151

5252
#ifdef CONFIG_EFI
53-
efi_system_table_t *systab;
53+
unsigned long systab, systab_tables, config_tables;
54+
unsigned int nr_tables;
5455
struct efi_info *ei;
5556
bool efi_64;
5657
int size, i;
@@ -70,46 +71,57 @@ static acpi_physical_address efi_get_rsdp_addr(void)
7071

7172
/* Get systab from boot params. */
7273
#ifdef CONFIG_X86_64
73-
systab = (efi_system_table_t *)(ei->efi_systab | ((__u64)ei->efi_systab_hi<<32));
74+
systab = ei->efi_systab | ((__u64)ei->efi_systab_hi << 32);
7475
#else
7576
if (ei->efi_systab_hi || ei->efi_memmap_hi) {
7677
debug_putstr("Error getting RSDP address: EFI system table located above 4GB.\n");
7778
return 0;
7879
}
79-
systab = (efi_system_table_t *)ei->efi_systab;
80+
systab = ei->efi_systab;
8081
#endif
8182
if (!systab)
8283
error("EFI system table not found.");
8384

84-
/*
85-
* Get EFI tables from systab.
86-
*/
87-
size = efi_64 ? sizeof(efi_config_table_64_t) :
88-
sizeof(efi_config_table_32_t);
85+
/* Handle EFI bitness properly */
86+
if (efi_64) {
87+
efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab;
88+
89+
config_tables = stbl->tables;
90+
nr_tables = stbl->nr_tables;
91+
size = sizeof(efi_config_table_64_t);
92+
} else {
93+
efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab;
8994

90-
for (i = 0; i < systab->nr_tables; i++) {
95+
config_tables = stbl->tables;
96+
nr_tables = stbl->nr_tables;
97+
size = sizeof(efi_config_table_32_t);
98+
}
99+
100+
if (!config_tables)
101+
error("EFI config tables not found.");
102+
103+
/* Get EFI tables from systab. */
104+
for (i = 0; i < nr_tables; i++) {
91105
acpi_physical_address table;
92-
void *config_tables;
93106
efi_guid_t guid;
94107

95-
config_tables = (void *)(systab->tables + size * i);
108+
config_tables += size;
109+
96110
if (efi_64) {
97-
efi_config_table_64_t *tmp_table;
111+
efi_config_table_64_t *tbl = (efi_config_table_64_t *)config_tables;
98112

99-
tmp_table = config_tables;
100-
guid = tmp_table->guid;
101-
table = tmp_table->table;
113+
guid = tbl->guid;
114+
table = tbl->table;
102115

103116
if (!IS_ENABLED(CONFIG_X86_64) && table >> 32) {
104117
debug_putstr("Error getting RSDP address: EFI config table located above 4GB.\n");
105118
return 0;
106119
}
107120
} else {
108-
efi_config_table_32_t *tmp_table;
121+
efi_config_table_32_t *tbl = (efi_config_table_32_t *)config_tables;
109122

110-
tmp_table = config_tables;
111-
guid = tmp_table->guid;
112-
table = tmp_table->table;
123+
guid = tbl->guid;
124+
table = tbl->table;
113125
}
114126

115127
if (!(efi_guidcmp(guid, ACPI_TABLE_GUID)))

0 commit comments

Comments
 (0)