aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efivars.c43
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;