diff options
author | Matt Fleming <matt.fleming@intel.com> | 2012-11-09 16:02:56 -0500 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2012-11-13 07:33:21 -0500 |
commit | 89d16665d388837b30972081d97b814be26d68a2 (patch) | |
tree | 0fd95e1e9d6886c27e7d9b7eed7464cd2e22988d /drivers/firmware | |
parent | cfcf2f11708f934d2bd294f973c2fcb0cc54f293 (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.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; |