aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/platform/efi/efi.c25
-rw-r--r--drivers/firmware/efivars.c18
-rw-r--r--include/linux/efi.h9
3 files changed, 36 insertions, 16 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 5f2ecaf3f9d8..c89c245eff40 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -999,3 +999,28 @@ u64 efi_mem_attributes(unsigned long phys_addr)
999 } 999 }
1000 return 0; 1000 return 0;
1001} 1001}
1002
1003/*
1004 * Some firmware has serious problems when using more than 50% of the EFI
1005 * variable store, i.e. it triggers bugs that can brick machines. Ensure that
1006 * we never use more than this safe limit.
1007 *
1008 * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
1009 * store.
1010 */
1011efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
1012{
1013 efi_status_t status;
1014 u64 storage_size, remaining_size, max_size;
1015
1016 status = efi.query_variable_info(attributes, &storage_size,
1017 &remaining_size, &max_size);
1018 if (status != EFI_SUCCESS)
1019 return status;
1020
1021 if (!storage_size || size > remaining_size || size > max_size ||
1022 (remaining_size - size) < (storage_size / 2))
1023 return EFI_OUT_OF_RESOURCES;
1024
1025 return EFI_SUCCESS;
1026}
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 7acafb80fd4c..bf15d81d74e1 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -436,24 +436,12 @@ static efi_status_t
436check_var_size_locked(struct efivars *efivars, u32 attributes, 436check_var_size_locked(struct efivars *efivars, u32 attributes,
437 unsigned long size) 437 unsigned long size)
438{ 438{
439 u64 storage_size, remaining_size, max_size;
440 efi_status_t status;
441 const struct efivar_operations *fops = efivars->ops; 439 const struct efivar_operations *fops = efivars->ops;
442 440
443 if (!efivars->ops->query_variable_info) 441 if (!efivars->ops->query_variable_store)
444 return EFI_UNSUPPORTED; 442 return EFI_UNSUPPORTED;
445 443
446 status = fops->query_variable_info(attributes, &storage_size, 444 return fops->query_variable_store(attributes, size);
447 &remaining_size, &max_size);
448
449 if (status != EFI_SUCCESS)
450 return status;
451
452 if (!storage_size || size > remaining_size || size > max_size ||
453 (remaining_size - size) < (storage_size / 2))
454 return EFI_OUT_OF_RESOURCES;
455
456 return status;
457} 445}
458 446
459 447
@@ -2131,7 +2119,7 @@ efivars_init(void)
2131 ops.get_variable = efi.get_variable; 2119 ops.get_variable = efi.get_variable;
2132 ops.set_variable = efi.set_variable; 2120 ops.set_variable = efi.set_variable;
2133 ops.get_next_variable = efi.get_next_variable; 2121 ops.get_next_variable = efi.get_next_variable;
2134 ops.query_variable_info = efi.query_variable_info; 2122 ops.query_variable_store = efi_query_variable_store;
2135 2123
2136 error = register_efivars(&__efivars, &ops, efi_kobj); 2124 error = register_efivars(&__efivars, &ops, efi_kobj);
2137 if (error) 2125 if (error)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9bf2f1fcae27..3d7df3d32c66 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -333,6 +333,7 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
333 unsigned long count, 333 unsigned long count,
334 u64 *max_size, 334 u64 *max_size,
335 int *reset_type); 335 int *reset_type);
336typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size);
336 337
337/* 338/*
338 * EFI Configuration Table and GUID definitions 339 * EFI Configuration Table and GUID definitions
@@ -575,9 +576,15 @@ extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if pos
575#ifdef CONFIG_X86 576#ifdef CONFIG_X86
576extern void efi_late_init(void); 577extern void efi_late_init(void);
577extern void efi_free_boot_services(void); 578extern void efi_free_boot_services(void);
579extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
578#else 580#else
579static inline void efi_late_init(void) {} 581static inline void efi_late_init(void) {}
580static inline void efi_free_boot_services(void) {} 582static inline void efi_free_boot_services(void) {}
583
584static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
585{
586 return EFI_SUCCESS;
587}
581#endif 588#endif
582extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr); 589extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
583extern u64 efi_get_iobase (void); 590extern u64 efi_get_iobase (void);
@@ -731,7 +738,7 @@ struct efivar_operations {
731 efi_get_variable_t *get_variable; 738 efi_get_variable_t *get_variable;
732 efi_get_next_variable_t *get_next_variable; 739 efi_get_next_variable_t *get_next_variable;
733 efi_set_variable_t *set_variable; 740 efi_set_variable_t *set_variable;
734 efi_query_variable_info_t *query_variable_info; 741 efi_query_variable_store_t *query_variable_store;
735}; 742};
736 743
737struct efivars { 744struct efivars {