From: Tristan Madani <tristmd@gmail.com>
To: Even Xu <even.xu@intel.com>, Jiri Kosina <jikos@kernel.org>,
Benjamin Tissoires <bentiss@kernel.org>
Cc: Xinpeng Sun <xinpeng.sun@intel.com>,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org,
Tristan Madani <tristan@talencesecurity.com>
Subject: [PATCH] HID: intel-thc-hid: validate ACPI buffer length before use
Date: Sat, 24 Oct 2026 20:58:50 +0000 [thread overview]
Message-ID: <20261024205850.4051206-1-tristmd@gmail.com> (raw)
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
next reply other threads:[~2026-10-24 20:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-24 20:58 Tristan Madani [this message]
2026-10-25 10:49 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261024205850.4051206-1-tristmd@gmail.com \
--to=tristmd@gmail.com \
--cc=bentiss@kernel.org \
--cc=even.xu@intel.com \
--cc=jikos@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=tristan@talencesecurity.com \
--cc=xinpeng.sun@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®