diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efivars.c | 43 |
1 files changed, 34 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; |