Skip to content

Commit 63056e8

Browse files
ardbiesheuvelIngo Molnar
authored andcommitted
efi/x86: Align GUIDs to their size in the mixed mode runtime wrapper
Hans reports that his mixed mode systems running v5.6-rc1 kernels hit the WARN_ON() in virt_to_phys_or_null_size(), caused by the fact that efi_guid_t objects on the vmap'ed stack happen to be misaligned with respect to their sizes. As a quick (i.e., backportable) fix, copy GUID pointer arguments to the local stack into a buffer that is naturally aligned to its size, so that it is guaranteed to cover only one physical page. Note that on x86, we cannot rely on the stack pointer being aligned the way the compiler expects, so we need to allocate an 8-byte aligned buffer of sufficient size, and copy the GUID into that buffer at an offset that is aligned to 16 bytes. Fixes: f6697df ("x86/efi: Prevent mixed mode boot corruption with CONFIG_VMAP_STACK=y") Reported-by: Hans de Goede <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Tested-by: Hans de Goede <[email protected]> Cc: [email protected] Cc: Ingo Molnar <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c5f8689 commit 63056e8

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

arch/x86/platform/efi/efi_64.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -658,15 +658,19 @@ static efi_status_t
658658
efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
659659
u32 *attr, unsigned long *data_size, void *data)
660660
{
661+
u8 buf[24] __aligned(8);
662+
efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
661663
efi_status_t status;
662664
u32 phys_name, phys_vendor, phys_attr;
663665
u32 phys_data_size, phys_data;
664666
unsigned long flags;
665667

666668
spin_lock_irqsave(&efi_runtime_lock, flags);
667669

670+
*vnd = *vendor;
671+
668672
phys_data_size = virt_to_phys_or_null(data_size);
669-
phys_vendor = virt_to_phys_or_null(vendor);
673+
phys_vendor = virt_to_phys_or_null(vnd);
670674
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
671675
phys_attr = virt_to_phys_or_null(attr);
672676
phys_data = virt_to_phys_or_null_size(data, *data_size);
@@ -683,14 +687,18 @@ static efi_status_t
683687
efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
684688
u32 attr, unsigned long data_size, void *data)
685689
{
690+
u8 buf[24] __aligned(8);
691+
efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
686692
u32 phys_name, phys_vendor, phys_data;
687693
efi_status_t status;
688694
unsigned long flags;
689695

690696
spin_lock_irqsave(&efi_runtime_lock, flags);
691697

698+
*vnd = *vendor;
699+
692700
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
693-
phys_vendor = virt_to_phys_or_null(vendor);
701+
phys_vendor = virt_to_phys_or_null(vnd);
694702
phys_data = virt_to_phys_or_null_size(data, data_size);
695703

696704
/* If data_size is > sizeof(u32) we've got problems */
@@ -707,15 +715,19 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
707715
u32 attr, unsigned long data_size,
708716
void *data)
709717
{
718+
u8 buf[24] __aligned(8);
719+
efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
710720
u32 phys_name, phys_vendor, phys_data;
711721
efi_status_t status;
712722
unsigned long flags;
713723

714724
if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
715725
return EFI_NOT_READY;
716726

727+
*vnd = *vendor;
728+
717729
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
718-
phys_vendor = virt_to_phys_or_null(vendor);
730+
phys_vendor = virt_to_phys_or_null(vnd);
719731
phys_data = virt_to_phys_or_null_size(data, data_size);
720732

721733
/* If data_size is > sizeof(u32) we've got problems */
@@ -732,21 +744,26 @@ efi_thunk_get_next_variable(unsigned long *name_size,
732744
efi_char16_t *name,
733745
efi_guid_t *vendor)
734746
{
747+
u8 buf[24] __aligned(8);
748+
efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
735749
efi_status_t status;
736750
u32 phys_name_size, phys_name, phys_vendor;
737751
unsigned long flags;
738752

739753
spin_lock_irqsave(&efi_runtime_lock, flags);
740754

755+
*vnd = *vendor;
756+
741757
phys_name_size = virt_to_phys_or_null(name_size);
742-
phys_vendor = virt_to_phys_or_null(vendor);
758+
phys_vendor = virt_to_phys_or_null(vnd);
743759
phys_name = virt_to_phys_or_null_size(name, *name_size);
744760

745761
status = efi_thunk(get_next_variable, phys_name_size,
746762
phys_name, phys_vendor);
747763

748764
spin_unlock_irqrestore(&efi_runtime_lock, flags);
749765

766+
*vendor = *vnd;
750767
return status;
751768
}
752769

0 commit comments

Comments
 (0)