Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82aa37cf authored by Dan Williams's avatar Dan Williams
Browse files

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: 0caeef63 ("libnvdimm: Add a poison list and export badblocks")
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent efda1b5d
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -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;