Commit 7022c495 authored by Ross Lagerwall's avatar Ross Lagerwall Committed by Greg Kroah-Hartman

efi: cper: Fix possible out-of-bounds access

[ Upstream commit 45b14a4f ]

When checking a generic status block, we iterate over all the generic
data blocks. The loop condition only checks that the start of the
generic data block is valid (within estatus->data_length) but not the
whole block. Because the size of data blocks (excluding error data) may
vary depending on the revision and the revision is contained within the
data block, ensure that enough of the current data block is valid before
dereferencing any members otherwise an out-of-bounds access may occur if
estatus->data_length is invalid.

This relies on the fact that struct acpi_hest_generic_data_v300 is a
superset of the earlier version.  Also rework the other checks to avoid
potential underflow.
Signed-off-by: default avatarRoss Lagerwall <ross.lagerwall@citrix.com>
Acked-by: default avatarBorislav Petkov <bp@suse.de>
Tested-by: default avatarTyler Baicar <baicar.tyler@gmail.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 33640a0c
...@@ -641,19 +641,24 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header); ...@@ -641,19 +641,24 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header);
int cper_estatus_check(const struct acpi_hest_generic_status *estatus) int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
{ {
struct acpi_hest_generic_data *gdata; struct acpi_hest_generic_data *gdata;
unsigned int data_len, gedata_len; unsigned int data_len, record_size;
int rc; int rc;
rc = cper_estatus_check_header(estatus); rc = cper_estatus_check_header(estatus);
if (rc) if (rc)
return rc; return rc;
data_len = estatus->data_length; data_len = estatus->data_length;
apei_estatus_for_each_section(estatus, gdata) { apei_estatus_for_each_section(estatus, gdata) {
gedata_len = acpi_hest_get_error_length(gdata); if (sizeof(struct acpi_hest_generic_data) > data_len)
if (gedata_len > data_len - acpi_hest_get_size(gdata)) return -EINVAL;
record_size = acpi_hest_get_record_size(gdata);
if (record_size > data_len)
return -EINVAL; return -EINVAL;
data_len -= acpi_hest_get_record_size(gdata);
data_len -= record_size;
} }
if (data_len) if (data_len)
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment