aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2016-12-06 15:45:24 -0500
committerDan Williams <dan.j.williams@intel.com>2016-12-06 19:30:37 -0500
commit82aa37cf09867c5e2c0326649d570e5b25c1189a (patch)
tree3da4c93548233667ba727b444ca4ab11ed4b47c4
parentefda1b5d87cbc3d8816f94a3815b413f1868e10d (diff)
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>
-rw-r--r--drivers/acpi/nfit/core.c21
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)
146 * then just continue with the returned results. 146 * then just continue with the returned results.
147 */ 147 */
148 if (status == NFIT_ARS_STATUS_INTR) { 148 if (status == NFIT_ARS_STATUS_INTR) {
149 if (ars_status->flags & NFIT_ARS_F_OVERFLOW) 149 if (ars_status->out_length >= 40 && (ars_status->flags
150 & NFIT_ARS_F_OVERFLOW))
150 return -ENOSPC; 151 return -ENOSPC;
151 return 0; 152 return 0;
152 } 153 }
@@ -2002,19 +2003,32 @@ static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
2002 return cmd_rc; 2003 return cmd_rc;
2003} 2004}
2004 2005
2005static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus, 2006static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc,
2006 struct nd_cmd_ars_status *ars_status) 2007 struct nd_cmd_ars_status *ars_status)
2007{ 2008{
2009 struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
2008 int rc; 2010 int rc;
2009 u32 i; 2011 u32 i;
2010 2012
2013 /*
2014 * First record starts at 44 byte offset from the start of the
2015 * payload.
2016 */
2017 if (ars_status->out_length < 44)
2018 return 0;
2011 for (i = 0; i < ars_status->num_records; i++) { 2019 for (i = 0; i < ars_status->num_records; i++) {
2020 /* only process full records */
2021 if (ars_status->out_length
2022 < 44 + sizeof(struct nd_ars_record) * (i + 1))
2023 break;
2012 rc = nvdimm_bus_add_poison(nvdimm_bus, 2024 rc = nvdimm_bus_add_poison(nvdimm_bus,
2013 ars_status->records[i].err_address, 2025 ars_status->records[i].err_address,
2014 ars_status->records[i].length); 2026 ars_status->records[i].length);
2015 if (rc) 2027 if (rc)
2016 return rc; 2028 return rc;
2017 } 2029 }
2030 if (i < ars_status->num_records)
2031 dev_warn(acpi_desc->dev, "detected truncated ars results\n");
2018 2032
2019 return 0; 2033 return 0;
2020} 2034}
@@ -2267,8 +2281,7 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
2267 if (rc < 0 && rc != -ENOSPC) 2281 if (rc < 0 && rc != -ENOSPC)
2268 return rc; 2282 return rc;
2269 2283
2270 if (ars_status_process_records(acpi_desc->nvdimm_bus, 2284 if (ars_status_process_records(acpi_desc, acpi_desc->ars_status))
2271 acpi_desc->ars_status))
2272 return -ENOMEM; 2285 return -ENOMEM;
2273 2286
2274 return 0; 2287 return 0;