aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-11-09 16:02:56 -0500
committerMatt Fleming <matt.fleming@intel.com>2012-11-13 07:33:21 -0500
commit89d16665d388837b30972081d97b814be26d68a2 (patch)
tree0fd95e1e9d6886c27e7d9b7eed7464cd2e22988d /drivers/firmware
parentcfcf2f11708f934d2bd294f973c2fcb0cc54f293 (diff)
efivarfs: Use query_variable_info() to limit kmalloc()
We don't want someone who can write EFI variables to be able to allocate arbitrarily large amounts of memory, so cap it to something sensible like the amount of free space for EFI variables. Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com> Cc: Matthew Garrett <mjg@redhat.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
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;