drivers/input/mouse/elan_i2c_core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
The Elan I2C touchpad driver queries the device for its physical
dimensions and trace counts to calculate the device resolution and width.
However, if the device firmware or device tree provides invalid zero
values for x_traces, y_traces, x_mm, or y_mm, it results in a fatal
division-by-zero exception leading to a kernel panic during device probe.
Add sanity checks to ensure these physical parameters are non-zero
before performing the division. If invalid values are detected, log an
error and return -EINVAL to gracefully abort the initialization and
maintain system stability.
Fixes: 6696777c6506 ("Input: add driver for Elan I2C/SMbus touchpad")
Fixes: e3a9a1290688 ("Input: elan_i2c - do not query the info if they are provided")
Signed-off-by: Ranjan Kumar <kumarranja@chromium.org>
---
drivers/input/mouse/elan_i2c_core.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index fee1796da3d0..b5fd63928afd 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -425,6 +425,14 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
if (error)
return error;
}
+
+ if (unlikely(x_traces == 0 || y_traces == 0)) {
+ dev_err(&client->dev,
+ "Invalid trace numbers: x=%u, y=%u\n",
+ x_traces, y_traces);
+ return -EINVAL;
+ }
+
data->width_x = data->max_x / x_traces;
data->width_y = data->max_y / y_traces;
@@ -440,6 +448,14 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
} else {
+
+ if (unlikely(x_mm == 0 || y_mm == 0)) {
+ dev_err(&client->dev,
+ "Invalid physical dimensions: x_mm=%u, y_mm=%u\n",
+ x_mm, y_mm);
+ return -EINVAL;
+ }
+
data->x_res = (data->max_x + 1) / x_mm;
data->y_res = (data->max_y + 1) / y_mm;
}
--
2.54.0.563.g4f69b47b94-goog
Hi Ranjan, On Wed, May 13, 2026 at 07:39:08AM +0000, Ranjan Kumar wrote: > The Elan I2C touchpad driver queries the device for its physical > dimensions and trace counts to calculate the device resolution and width. > However, if the device firmware or device tree provides invalid zero > values for x_traces, y_traces, x_mm, or y_mm, it results in a fatal > division-by-zero exception leading to a kernel panic during device probe. > Neither crashing nor aborting probe with -EINVAL is great as we will not be able to flash another firmware. How do we get into this state? Is this something actually observed or just theoretical? > Add sanity checks to ensure these physical parameters are non-zero > before performing the division. If invalid values are detected, log an > error and return -EINVAL to gracefully abort the initialization and > maintain system stability. That is hardly "stability" for a laptop when its pointer is not working. Thanks. -- Dmitry
The Elan I2C touchpad driver queries the device for its physical
dimensions and trace counts to calculate the device resolution and width.
However, if the device firmware or device tree provides invalid zero
values for x_traces, y_traces, x_mm, or y_mm, it results in a fatal
division-by-zero exception leading to a kernel panic during device probe.
Add sanity checks to ensure these physical parameters are non-zero
before performing the division. If invalid values are detected, log a
warning and fall back to safe default values (1) to safely bypass the
division.
This prevents the kernel panic while allowing the probe to complete
successfully. Completing the probe ensures the sysfs nodes are created,
keeping the firmware update path intact so a recovery firmware can be
flashed to the device.
Fixes: 6696777c6506 ("Input: add driver for Elan I2C/SMbus touchpad")
Fixes: e3a9a1290688 ("Input: elan_i2c - do not query the info if they are provided")
Signed-off-by: Ranjan Kumar <kumarranja@chromium.org>
---
Changes in v2:
- Changed error handling from aborting probe with -EINVAL to logging a
warning and falling back to default values (1).
- Bypassing the division instead of aborting preserves the sysfs
interface for firmware updates and keeps the pointer functional.
drivers/input/mouse/elan_i2c_core.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index fee1796da3d0..32b2849ab36a 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -425,8 +425,17 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
if (error)
return error;
}
- data->width_x = data->max_x / x_traces;
- data->width_y = data->max_y / y_traces;
+
+ if (unlikely(x_traces == 0 || y_traces == 0)) {
+ dev_warn(&client->dev,
+ "invalid trace numbers: x=%u, y=%u\n",
+ x_traces, y_traces);
+ data->width_x = 1;
+ data->width_y = 1;
+ } else {
+ data->width_x = data->max_x / x_traces;
+ data->width_y = data->max_y / y_traces;
+ }
if (device_property_read_u32(&client->dev,
"touchscreen-x-mm", &x_mm) ||
@@ -440,8 +449,16 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
} else {
- data->x_res = (data->max_x + 1) / x_mm;
- data->y_res = (data->max_y + 1) / y_mm;
+ if (unlikely(x_mm == 0 || y_mm == 0)) {
+ dev_warn(&client->dev,
+ "invalid physical dimensions: x_mm=%u, y_mm=%u\n",
+ x_mm, y_mm);
+ data->x_res = 1;
+ data->y_res = 1;
+ } else {
+ data->x_res = (data->max_x + 1) / x_mm;
+ data->y_res = (data->max_y + 1) / y_mm;
+ }
}
if (device_property_read_bool(&client->dev, "elan,clickpad"))
--
2.54.0.563.g4f69b47b94-goog
© 2016 - 2026 Red Hat, Inc.