From 8a415b8c05f261a52f45f2271b6c4731376fd5b5 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 29 Apr 2013 20:08:02 +0100 Subject: [PATCH] efi, pstore: Read data from variable store before memcpy() Seiji reported getting empty dmesg-* files, because the data was never actually read in efi_pstore_read_func(), and so the memcpy() was copying garbage data. This patch necessitated adding __efivar_entry_get() which is callable between efivar_entry_iter_{begin,end}(). We can also delete __efivar_entry_size() because efi_pstore_read_func() was the only caller. Reported-by: Seiji Aguchi Tested-by: Seiji Aguchi Cc: Tony Luck Cc: Matthew Garrett Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-pstore.c | 6 +++- drivers/firmware/efi/vars.c | 53 ++++++++++++++++--------------- include/linux/efi.h | 3 +- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index af45c42086e1..67615d6d038d 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -73,7 +73,11 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) } else return 0; - __efivar_entry_size(entry, &size); + entry->var.DataSize = 1024; + __efivar_entry_get(entry, &entry->var.Attributes, + &entry->var.DataSize, entry->var.Data); + size = entry->var.DataSize; + *cb_data->buf = kmalloc(size, GFP_KERNEL); if (*cb_data->buf == NULL) return -ENOMEM; diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 1d80c1ca39c5..96d328b21c3e 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -688,32 +688,6 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, } EXPORT_SYMBOL_GPL(efivar_entry_find); -/** - * __efivar_entry_size - obtain the size of a variable - * @entry: entry for this variable - * @size: location to store the variable's size - * - * The caller MUST call efivar_entry_iter_begin() and - * efivar_entry_iter_end() before and after the invocation of this - * function, respectively. - */ -int __efivar_entry_size(struct efivar_entry *entry, unsigned long *size) -{ - const struct efivar_operations *ops = __efivars->ops; - efi_status_t status; - - WARN_ON(!spin_is_locked(&__efivars->lock)); - - *size = 0; - status = ops->get_variable(entry->var.VariableName, - &entry->var.VendorGuid, NULL, size, NULL); - if (status != EFI_BUFFER_TOO_SMALL) - return efi_status_to_err(status); - - return 0; -} -EXPORT_SYMBOL_GPL(__efivar_entry_size); - /** * efivar_entry_size - obtain the size of a variable * @entry: entry for this variable @@ -738,6 +712,33 @@ int efivar_entry_size(struct efivar_entry *entry, unsigned long *size) } EXPORT_SYMBOL_GPL(efivar_entry_size); +/** + * __efivar_entry_get - call get_variable() + * @entry: read data for this variable + * @attributes: variable attributes + * @size: size of @data buffer + * @data: buffer to store variable data + * + * The caller MUST call efivar_entry_iter_begin() and + * efivar_entry_iter_end() before and after the invocation of this + * function, respectively. + */ +int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, + unsigned long *size, void *data) +{ + const struct efivar_operations *ops = __efivars->ops; + efi_status_t status; + + WARN_ON(!spin_is_locked(&__efivars->lock)); + + status = ops->get_variable(entry->var.VariableName, + &entry->var.VendorGuid, + attributes, size, data); + + return efi_status_to_err(status); +} +EXPORT_SYMBOL_GPL(__efivar_entry_get); + /** * efivar_entry_get - call get_variable() * @entry: read data for this variable diff --git a/include/linux/efi.h b/include/linux/efi.h index 3f7257f1f5e8..2bc0ad78d058 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -808,8 +808,9 @@ void efivar_entry_remove(struct efivar_entry *entry); int __efivar_entry_delete(struct efivar_entry *entry); int efivar_entry_delete(struct efivar_entry *entry); -int __efivar_entry_size(struct efivar_entry *entry, unsigned long *size); int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); +int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, + unsigned long *size, void *data); int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, unsigned long *size, void *data); int efivar_entry_set(struct efivar_entry *entry, u32 attributes,