diff options
| -rw-r--r-- | drivers/firmware/efivars.c | 43 | ||||
| -rw-r--r-- | include/linux/efi.h | 1 |
2 files changed, 35 insertions, 9 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 9ac934018bba..d6b8d2f628fa 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
| @@ -694,28 +694,51 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
| 694 | struct inode *inode = file->f_mapping->host; | 694 | struct inode *inode = file->f_mapping->host; |
| 695 | unsigned long datasize = count - sizeof(attributes); | 695 | unsigned long datasize = count - sizeof(attributes); |
| 696 | unsigned long newdatasize; | 696 | unsigned long newdatasize; |
| 697 | u64 storage_size, remaining_size, max_size; | ||
| 697 | ssize_t bytes = 0; | 698 | ssize_t bytes = 0; |
| 698 | 699 | ||
| 699 | if (count < sizeof(attributes)) | 700 | if (count < sizeof(attributes)) |
| 700 | return -EINVAL; | 701 | return -EINVAL; |
| 701 | 702 | ||
| 702 | data = kmalloc(datasize, GFP_KERNEL); | 703 | if (copy_from_user(&attributes, userbuf, sizeof(attributes))) |
| 704 | return -EFAULT; | ||
| 703 | 705 | ||
| 704 | if (!data) | 706 | if (attributes & ~(EFI_VARIABLE_MASK)) |
| 705 | return -ENOMEM; | 707 | return -EINVAL; |
| 706 | 708 | ||
| 707 | efivars = var->efivars; | 709 | efivars = var->efivars; |
| 708 | 710 | ||
| 709 | if (copy_from_user(&attributes, userbuf, sizeof(attributes))) { | 711 | /* |
| 710 | bytes = -EFAULT; | 712 | * Ensure that the user can't allocate arbitrarily large |
| 711 | goto out; | 713 | * amounts of memory. Pick a default size of 64K if |
| 714 | * QueryVariableInfo() isn't supported by the firmware. | ||
| 715 | */ | ||
| 716 | spin_lock(&efivars->lock); | ||
| 717 | |||
| 718 | if (!efivars->ops->query_variable_info) | ||
| 719 | status = EFI_UNSUPPORTED; | ||
| 720 | else { | ||
| 721 | const struct efivar_operations *fops = efivars->ops; | ||
| 722 | status = fops->query_variable_info(attributes, &storage_size, | ||
| 723 | &remaining_size, &max_size); | ||
| 712 | } | 724 | } |
| 713 | 725 | ||
| 714 | if (attributes & ~(EFI_VARIABLE_MASK)) { | 726 | spin_unlock(&efivars->lock); |
| 715 | bytes = -EINVAL; | 727 | |
| 716 | goto out; | 728 | if (status != EFI_SUCCESS) { |
| 729 | if (status != EFI_UNSUPPORTED) | ||
| 730 | return efi_status_to_err(status); | ||
| 731 | |||
| 732 | remaining_size = 65536; | ||
| 717 | } | 733 | } |
| 718 | 734 | ||
| 735 | if (datasize > remaining_size) | ||
| 736 | return -ENOSPC; | ||
| 737 | |||
| 738 | data = kmalloc(datasize, GFP_KERNEL); | ||
| 739 | if (!data) | ||
| 740 | return -ENOMEM; | ||
| 741 | |||
| 719 | if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) { | 742 | if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) { |
| 720 | bytes = -EFAULT; | 743 | bytes = -EFAULT; |
| 721 | goto out; | 744 | goto out; |
| @@ -1709,6 +1732,8 @@ efivars_init(void) | |||
| 1709 | ops.get_variable = efi.get_variable; | 1732 | ops.get_variable = efi.get_variable; |
| 1710 | ops.set_variable = efi.set_variable; | 1733 | ops.set_variable = efi.set_variable; |
| 1711 | ops.get_next_variable = efi.get_next_variable; | 1734 | ops.get_next_variable = efi.get_next_variable; |
| 1735 | ops.query_variable_info = efi.query_variable_info; | ||
| 1736 | |||
| 1712 | error = register_efivars(&__efivars, &ops, efi_kobj); | 1737 | error = register_efivars(&__efivars, &ops, efi_kobj); |
| 1713 | if (error) | 1738 | if (error) |
| 1714 | goto err_put; | 1739 | goto err_put; |
diff --git a/include/linux/efi.h b/include/linux/efi.h index 5e2308d9c6be..f80079cd84f4 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
| @@ -646,6 +646,7 @@ struct efivar_operations { | |||
| 646 | efi_get_variable_t *get_variable; | 646 | efi_get_variable_t *get_variable; |
| 647 | efi_get_next_variable_t *get_next_variable; | 647 | efi_get_next_variable_t *get_next_variable; |
| 648 | efi_set_variable_t *set_variable; | 648 | efi_set_variable_t *set_variable; |
| 649 | efi_query_variable_info_t *query_variable_info; | ||
| 649 | }; | 650 | }; |
| 650 | 651 | ||
| 651 | struct efivars { | 652 | struct efivars { |
