diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-12-06 12:45:24 -0800 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-12-06 16:30:37 -0800 |
commit | 82aa37cf09867c5e2c0326649d570e5b25c1189a (patch) | |
tree | 3da4c93548233667ba727b444ca4ab11ed4b47c4 /drivers/acpi | |
parent | efda1b5d87cbc3d8816f94a3815b413f1868e10d (diff) | |
download | linux-82aa37cf09867c5e2c0326649d570e5b25c1189a.tar.bz2 |
acpi, nfit: validate ars_status output buffer size
If an ARS Status command returns truncated output, do not process
partial records or otherwise consume non-status fields.
Cc: <stable@vger.kernel.org>
Fixes: 0caeef63e6d2 ("libnvdimm: Add a poison list and export badblocks")
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/nfit/core.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index e58ec32393b7..4b8b4f520d76 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -146,7 +146,8 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status) * then just continue with the returned results. */ if (status == NFIT_ARS_STATUS_INTR) { - if (ars_status->flags & NFIT_ARS_F_OVERFLOW) + if (ars_status->out_length >= 40 && (ars_status->flags + & NFIT_ARS_F_OVERFLOW)) return -ENOSPC; return 0; } @@ -2002,19 +2003,32 @@ static int ars_get_status(struct acpi_nfit_desc *acpi_desc) return cmd_rc; } -static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus, +static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc, struct nd_cmd_ars_status *ars_status) { + struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus; int rc; u32 i; + /* + * First record starts at 44 byte offset from the start of the + * payload. + */ + if (ars_status->out_length < 44) + return 0; for (i = 0; i < ars_status->num_records; i++) { + /* only process full records */ + if (ars_status->out_length + < 44 + sizeof(struct nd_ars_record) * (i + 1)) + break; rc = nvdimm_bus_add_poison(nvdimm_bus, ars_status->records[i].err_address, ars_status->records[i].length); if (rc) return rc; } + if (i < ars_status->num_records) + dev_warn(acpi_desc->dev, "detected truncated ars results\n"); return 0; } @@ -2267,8 +2281,7 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc, if (rc < 0 && rc != -ENOSPC) return rc; - if (ars_status_process_records(acpi_desc->nvdimm_bus, - acpi_desc->ars_status)) + if (ars_status_process_records(acpi_desc, acpi_desc->ars_status)) return -ENOMEM; return 0; |