Skip to content

Commit df2b818

Browse files
Ranjan Kumardtor
authored andcommitted
Input: elan_i2c - prevent division by zero and arithmetic underflow
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 or y_traces, it results in a fatal division-by-zero exception leading to a kernel panic during device probe. Add checks to ensure these parameters are non-zero before performing the division. If invalid trace values are detected, fall back to a safe default of 1. Additionally, prevent an arithmetic underflow in the touch reporting logic. Previously, if the calculated or fallback width was smaller than ETP_FWIDTH_REDUCE (90), the subtraction would underflow, resulting in a massive unsigned integer being reported to userspace. Clamp the adjusted width to a minimum of 0 to safely handle small physical dimensions and fallback scenarios. Completing the probe with safe fallback values ensures the sysfs nodes are created, keeping the firmware update path intact so a recovery firmware can be flashed to the device. Fixes: 6696777 ("Input: add driver for Elan I2C/SMbus touchpad") Fixes: e3a9a12 ("Input: elan_i2c - do not query the info if they are provided") Signed-off-by: Ranjan Kumar <kumarranja@chromium.org> Link: https://patch.msgid.link/20260612060339.3829666-1-kumarranja@chromium.org Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
1 parent ef166ce commit df2b818

1 file changed

Lines changed: 30 additions & 6 deletions

File tree

drivers/input/mouse/elan_i2c_core.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,17 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
428428
if (error)
429429
return error;
430430
}
431-
data->width_x = data->max_x / x_traces;
432-
data->width_y = data->max_y / y_traces;
431+
432+
if (!x_traces || !y_traces) {
433+
dev_warn(&client->dev,
434+
"invalid trace numbers: x=%u, y=%u\n",
435+
x_traces, y_traces);
436+
data->width_x = 1;
437+
data->width_y = 1;
438+
} else {
439+
data->width_x = data->max_x / x_traces;
440+
data->width_y = data->max_y / y_traces;
441+
}
433442

434443
if (device_property_read_u32(&client->dev,
435444
"touchscreen-x-mm", &x_mm) ||
@@ -443,8 +452,16 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
443452
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
444453
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
445454
} else {
446-
data->x_res = (data->max_x + 1) / x_mm;
447-
data->y_res = (data->max_y + 1) / y_mm;
455+
if (unlikely(x_mm == 0 || y_mm == 0)) {
456+
dev_warn(&client->dev,
457+
"invalid physical dimensions: x_mm=%u, y_mm=%u\n",
458+
x_mm, y_mm);
459+
data->x_res = 1;
460+
data->y_res = 1;
461+
} else {
462+
data->x_res = (data->max_x + 1) / x_mm;
463+
data->y_res = (data->max_y + 1) / y_mm;
464+
}
448465
}
449466

450467
if (device_property_read_bool(&client->dev, "elan,clickpad"))
@@ -956,6 +973,7 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num,
956973

957974
if (data->report_features & ETP_FEATURE_REPORT_MK) {
958975
unsigned int mk_x, mk_y, area_x, area_y;
976+
int adj_width_x, adj_width_y;
959977
u8 mk_data = high_precision ?
960978
packet[ETP_MK_DATA_OFFSET + contact_num] :
961979
finger_data[3];
@@ -967,8 +985,14 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num,
967985
* To avoid treating large finger as palm, let's reduce
968986
* the width x and y per trace.
969987
*/
970-
area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
971-
area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
988+
989+
adj_width_x = data->width_x > ETP_FWIDTH_REDUCE ?
990+
data->width_x - ETP_FWIDTH_REDUCE : 0;
991+
adj_width_y = data->width_y > ETP_FWIDTH_REDUCE ?
992+
data->width_y - ETP_FWIDTH_REDUCE : 0;
993+
994+
area_x = mk_x * adj_width_x;
995+
area_y = mk_y * adj_width_y;
972996

973997
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
974998
input_report_abs(input, ABS_MT_TOUCH_MAJOR,

0 commit comments

Comments
 (0)