[PATCH] efi: vars: commonize the 512-byte name buffer quirk

Jonggeun Park <[email protected]>
Newsgroups org.kernel.vger.linux-efi,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Some old UEFI implementations reject GetNextVariableName() calls with
a name buffer size larger than 512 bytes. Both efivar_init() and
efi_pstore_read() open-code the same workaround of resetting the size
to 512 on every iteration.

Introduce efivar_get_next_variable_safe() which keeps this quirk in a
single place, resolving the TODO in efi-pstore.c.

No functional change intended.

Signed-off-by: Jonggeun Park <[email protected]>
---
 drivers/firmware/efi/efi-pstore.c | 16 +++++-----------
 drivers/firmware/efi/vars.c       | 21 +++++++++++++++++++++
 fs/efivarfs/vars.c                |  4 +---
 include/linux/efi.h               |  4 ++++
 4 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index a5db3534f..a135d6e2f 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -164,16 +164,6 @@ static ssize_t efi_pstore_read(struct pstore_record *record)
 	efi_status_t status;
 
 	for (;;) {
-		/*
-		 * A small set of old UEFI implementations reject sizes
-		 * above a certain threshold, the lowest seen in the wild
-		 * is 512.
-		 *
-		 * TODO: Commonize with the iteration implementation in
-		 *       fs/efivarfs to keep all the quirks in one place.
-		 */
-		varname_size = 512;
-
 		/*
 		 * If this is the first read() call in the pstore enumeration,
 		 * varname will be the empty string, and the GetNextVariable()
@@ -185,8 +175,12 @@ static ssize_t efi_pstore_read(struct pstore_record *record)
 		 * store varname in record->psi->data. Given that we only
 		 * enumerate variables with the efi-pstore GUID, there is no
 		 * need to record the guid return value.
+		 *
+		 * The 512-byte name buffer quirk is handled inside
+		 * efivar_get_next_variable_safe().
 		 */
-		status = efivar_get_next_variable(&varname_size, varname, &guid);
+		status = efivar_get_next_variable_safe(&varname_size, varname,
+						       &guid);
 		if (status == EFI_NOT_FOUND)
 			return 0;
 
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index 3700e9869..8e69f3632 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -265,3 +265,24 @@ efi_status_t efivar_query_variable_info(u32 attr,
 			remaining_space, max_variable_size);
 }
 EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, "EFIVAR");
+
+/*
+ * efivar_get_next_variable_safe() - enumerate the next name/vendor pair
+ *
+ * Wrapper around efivar_get_next_variable() that keeps the 512-byte name
+ * buffer quirk in one place. Some old UEFI implementations reject name buffer
+ * sizes larger than 512 bytes (the lowest seen in the wild), so this always
+ * requests 512 bytes; callers must provide a buffer of at least that size.
+ *
+ * Must be called with efivars_lock held.
+ */
+efi_status_t efivar_get_next_variable_safe(unsigned long *name_size,
+					   efi_char16_t *name,
+					   efi_guid_t *vendor)
+{
+	BUILD_BUG_ON(EFI_VAR_NAME_LEN < 512);
+	*name_size = 512;
+
+	return efivar_get_next_variable(name_size, name, vendor);
+}
+EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable_safe, "EFIVAR");
diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c
index 6833c3d24..ee55a26cb 100644
--- a/fs/efivarfs/vars.c
+++ b/fs/efivarfs/vars.c
@@ -398,10 +398,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
 	 */
 
 	do {
-		variable_name_size = 512;
-		BUILD_BUG_ON(EFI_VAR_NAME_LEN < 512);
 
-		status = efivar_get_next_variable(&variable_name_size,
+		status = efivar_get_next_variable_safe(&variable_name_size,
 						  variable_name,
 						  &vendor_guid);
 		switch (status) {
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ccbc35479..f36505aa0 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1076,6 +1076,10 @@ efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
 efi_status_t efivar_get_next_variable(unsigned long *name_size,
 				      efi_char16_t *name, efi_guid_t *vendor);
 
+efi_status_t efivar_get_next_variable_safe(unsigned long *name_size,
+					   efi_char16_t *name,
+					   efi_guid_t *vendor);
+
 efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
 					u32 attr, unsigned long data_size,
 					void *data, bool nonblocking);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.