diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-12-06 15:45:24 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-12-06 19:30:37 -0500 |
commit | 82aa37cf09867c5e2c0326649d570e5b25c1189a (patch) | |
tree | 3da4c93548233667ba727b444ca4ab11ed4b47c4 | |
parent | efda1b5d87cbc3d8816f94a3815b413f1868e10d (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.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) | |||
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 | ||
2005 | static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus, | 2006 | static 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; |