From: Tristan Madani thc_acpi_get_property() copies firmware-returned ACPI buffers into caller-provided structures without verifying the buffer length. Malformed or short ACPI tables could cause an out-of-bounds read from the firmware buffer, and oversized responses could overflow the destination struct. Add a buf_size parameter and reject responses larger than the destination buffer. Accept shorter responses to handle firmware that returns buffers without struct tail padding (e.g. 1 byte for a 4-byte SPI opcode field). Zero-initialize caller stack structures so fields beyond the firmware response length are deterministic. Fixes: 7cb06f08ef13 ("HID: intel-thc-hid: intel-quickspi: Add THC QuickSPI ACPI interfaces") Cc: stable@vger.kernel.org Reviewed-by: Even Xu Signed-off-by: Tristan Madani --- .../intel-quickspi/pci-quickspi.c | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c index ad676fde211b6..deca020a46497 100644 --- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c +++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c @@ -75,13 +75,15 @@ static const struct acpi_gpio_mapping quickspi_gpios[] = { * @func: ACPI method's function number * @type: ACPI parameter's data type * @prop_buf: point to return buffer + * @buf_size: size of @prop_buf in bytes (0 to skip length check) * * This is a helper function for device to query its ACPI parameters. * * Return: 0 if successful or ENODEV on failed. */ static int thc_acpi_get_property(struct acpi_device *adev, const guid_t *guid, - u64 rev, u64 func, acpi_object_type type, void *prop_buf) + u64 rev, u64 func, acpi_object_type type, + void *prop_buf, size_t buf_size) { acpi_handle handle = acpi_device_handle(adev); union acpi_object *obj; @@ -94,10 +96,15 @@ static int thc_acpi_get_property(struct acpi_device *adev, const guid_t *guid, return -ENODEV; } - if (type == ACPI_TYPE_INTEGER) + if (type == ACPI_TYPE_INTEGER) { *(u32 *)prop_buf = (u32)obj->integer.value; - else if (type == ACPI_TYPE_BUFFER) + } else if (type == ACPI_TYPE_BUFFER) { + if (buf_size > 0 && obj->buffer.length > buf_size) { + ACPI_FREE(obj); + return -ENOSPC; + } memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length); + } ACPI_FREE(obj); @@ -129,7 +136,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_HDR_ADDR, ACPI_TYPE_INTEGER, - &qsdev->input_report_hdr_addr); + &qsdev->input_report_hdr_addr, 0); if (ret) return ret; @@ -137,7 +144,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_BDY_ADDR, ACPI_TYPE_INTEGER, - &qsdev->input_report_bdy_addr); + &qsdev->input_report_bdy_addr, 0); if (ret) return ret; @@ -145,7 +152,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_OUTPUT_REP_ADDR, ACPI_TYPE_INTEGER, - &qsdev->output_report_addr); + &qsdev->output_report_addr, 0); if (ret) return ret; @@ -153,7 +160,8 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_READ_OPCODE, ACPI_TYPE_BUFFER, - &qsdev->spi_read_opcode); + &qsdev->spi_read_opcode, + sizeof(qsdev->spi_read_opcode)); if (ret) return ret; @@ -161,7 +169,8 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_WRITE_OPCODE, ACPI_TYPE_BUFFER, - &qsdev->spi_write_opcode); + &qsdev->spi_write_opcode, + sizeof(qsdev->spi_write_opcode)); if (ret) return ret; @@ -169,7 +178,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_IO_MODE, ACPI_TYPE_INTEGER, - &qsdev->spi_read_io_mode); + &qsdev->spi_read_io_mode, 0); if (ret) return ret; @@ -184,7 +193,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_CONNECTION_SPEED, ACPI_TYPE_INTEGER, - &qsdev->spi_freq_val); + &qsdev->spi_freq_val, 0); if (ret) return ret; @@ -192,7 +201,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_LIMIT_PACKET_SIZE, ACPI_TYPE_INTEGER, - &qsdev->limit_packet_size); + &qsdev->limit_packet_size, 0); if (ret) return ret; @@ -205,7 +214,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_PERFORMANCE_LIMIT, ACPI_TYPE_INTEGER, - &qsdev->performance_limit); + &qsdev->performance_limit, 0); if (ret) return ret; @@ -215,7 +224,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_ACTIVE_LTR, ACPI_TYPE_INTEGER, - &qsdev->active_ltr_val); + &qsdev->active_ltr_val, 0); if (ret) return ret; @@ -223,7 +232,7 @@ static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) ACPI_QUICKSPI_REVISION_NUM, ACPI_QUICKSPI_FUNC_NUM_LP_LTR, ACPI_TYPE_INTEGER, - &qsdev->low_power_ltr_val); + &qsdev->low_power_ltr_val, 0); if (ret) return ret; -- 2.47.3