* [PATCH] HID: intel-thc-hid: validate ACPI buffer length before use
@ 2026-10-24 20:58 Tristan Madani
0 siblings, 0 replies; only message in thread
From: Tristan Madani @ 2026-10-24 20:58 UTC (permalink / raw)
To: Even Xu, Jiri Kosina, Benjamin Tissoires
Cc: Xinpeng Sun, linux-input, linux-kernel, stable, Tristan Madani
From: Tristan Madani <tristan@talencesecurity.com>
The QuickI2C and QuickSPI ACPI helpers copy firmware-returned buffers
into fixed-layout caller structs without checking the buffer length
against the destination size:
1. Buffer copies use the firmware-reported length without checking
it against the destination buffer size, allowing stack overflows
from oversized responses.
2. Undersized buffer responses leave caller struct fields
uninitialized, as fixed-layout structs like i2c_param and
i2c_config are consumed field-by-field after the call.
3. The QuickI2C DSD helper does not validate the returned ACPI
object type before accessing buffer-specific fields.
Add a buf_size parameter to all three helpers and enforce exact
buffer size matching for BUFFER type properties. Add type validation
in the DSD helper (the DSM helpers already receive type-checked
results from acpi_evaluate_dsm_typed()).
Fixes: 5282e45ccbfa ("HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C ACPI interfaces")
Fixes: 7cb06f08ef13 ("HID: intel-thc-hid: intel-quickspi: Add THC QuickSPI ACPI interfaces")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
.../intel-quicki2c/pci-quicki2c.c | 40 ++++++++++++++----
.../intel-quickspi/pci-quickspi.c | 41 ++++++++++++-------
2 files changed, 58 insertions(+), 23 deletions(-)
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
index 2537288b50261..a3d71f296b462 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
@@ -62,7 +62,8 @@ static const struct acpi_gpio_mapping quicki2c_gpios[] = {
* Return: 0 if success or ENODEV on failure.
*/
static int quicki2c_acpi_get_dsm_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;
@@ -75,10 +76,17 @@ static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t
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) {
+ int err = obj->buffer.length > buf_size ? -ENOSPC : -EINVAL;
+
+ ACPI_FREE(obj);
+ return err;
+ }
memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length);
+ }
ACPI_FREE(obj);
@@ -97,7 +105,8 @@ static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t
* Return: 0 if success or ENODEV on failed.
*/
static int quicki2c_acpi_get_dsd_property(struct acpi_device *adev, acpi_string dsd_method_name,
- acpi_object_type type, void *prop_buf)
+ acpi_object_type type, void *prop_buf,
+ size_t buf_size)
{
acpi_handle handle = acpi_device_handle(adev);
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -113,7 +122,18 @@ static int quicki2c_acpi_get_dsd_property(struct acpi_device *adev, acpi_string
ret_obj = buffer.pointer;
+ if (ret_obj->type != type) {
+ kfree(buffer.pointer);
+ return -EINVAL;
+ }
+ if (buf_size > 0 && ret_obj->buffer.length != buf_size) {
+ int err = ret_obj->buffer.length > buf_size ? -ENOSPC : -EINVAL;
+
+ kfree(buffer.pointer);
+ return err;
+ }
memcpy(prop_buf, ret_obj->buffer.pointer, ret_obj->buffer.length);
+ kfree(buffer.pointer);
return 0;
}
@@ -145,7 +165,7 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
QUICKI2C_ACPI_REVISION_NUM,
QUICKI2C_ACPI_FUNC_NUM_HID_DESC_ADDR,
ACPI_TYPE_INTEGER,
- &hid_desc_addr);
+ &hid_desc_addr, 0);
if (ret)
return ret;
@@ -155,7 +175,7 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
QUICKI2C_ACPI_REVISION_NUM,
QUICKI2C_ACPI_FUNC_NUM_ACTIVE_LTR_VAL,
ACPI_TYPE_INTEGER,
- &qcdev->active_ltr_val);
+ &qcdev->active_ltr_val, 0);
if (ret)
return ret;
@@ -163,12 +183,13 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
QUICKI2C_ACPI_REVISION_NUM,
QUICKI2C_ACPI_FUNC_NUM_LP_LTR_VAL,
ACPI_TYPE_INTEGER,
- &qcdev->low_power_ltr_val);
+ &qcdev->low_power_ltr_val, 0);
if (ret)
return ret;
ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ICRS,
- ACPI_TYPE_BUFFER, &i2c_param);
+ ACPI_TYPE_BUFFER, &i2c_param,
+ sizeof(i2c_param));
if (ret)
return ret;
@@ -180,7 +201,8 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
qcdev->i2c_config.target_addr = i2c_param.device_address;
ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ISUB,
- ACPI_TYPE_BUFFER, &i2c_config);
+ ACPI_TYPE_BUFFER, &i2c_config,
+ sizeof(i2c_config));
if (ret)
return ret;
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..ec15ded2e91ea 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
@@ -81,7 +81,8 @@ static const struct acpi_gpio_mapping quickspi_gpios[] = {
* 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 +95,20 @@ 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) {
+ int err = obj->buffer.length > buf_size ? -ENOSPC : -EINVAL;
+
+ acpi_handle_err(handle,
+ "_DSM buffer size mismatch: %llu vs %zu\n",
+ (unsigned long long)obj->buffer.length, buf_size);
+ ACPI_FREE(obj);
+ return err;
+ }
memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length);
+ }
ACPI_FREE(obj);
@@ -129,7 +140,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 +148,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 +156,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 +164,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 +173,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 +182,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 +197,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 +205,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 +218,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 +228,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 +236,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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-24 20:58 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-24 20:58 [PATCH] HID: intel-thc-hid: validate ACPI buffer length before use Tristan Madani
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®