From 8fcd8136674073d4841b36930cf4775e81fa0dde Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Mon, 2 Feb 2015 00:21:27 +0100 Subject: [PATCH] Fix incorrect handling of multiple SLOTSTATE_CLOSE/SLOTSTATE_OPEN events happening in one SYN_REPORT data packet leading to (priv->num_active_touches > priv->num_slots) bug and eventually to SIGSEGV Signed-off-by: Thilo Schulz --- src/eventcomm.c | 86 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/src/eventcomm.c b/src/eventcomm.c index 53a0ca4..3aa42e9 100644 --- a/src/eventcomm.c +++ b/src/eventcomm.c @@ -80,6 +80,13 @@ struct eventcomm_proto_data { * exists for readability of the code. */ BOOL need_grab; + + /* + * Does the last_ev member of this struct contain a valid event for + * processing? + */ + BOOL process_ev; + int st_to_mt_offset[2]; double st_to_mt_scale[2]; int axis_map[ABS_MT_CNT]; @@ -91,6 +98,7 @@ struct eventcomm_proto_data { enum libevdev_read_flag read_flag; int have_monotonic_clock; + struct input_event last_ev; }; #ifdef HAVE_LIBEVDEV_DEVICE_LOG_FUNCS @@ -574,7 +582,7 @@ EventTouchSlotPreviouslyOpen(SynapticsPrivate * priv, int slot) return FALSE; } -static void +static Bool EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw, struct input_event *ev) { @@ -582,7 +590,7 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw, struct eventcomm_proto_data *proto_data = priv->proto_data; if (!priv->has_touch) - return; + return TRUE; if (ev->code == ABS_MT_SLOT) { proto_data->cur_slot = ev->value; @@ -591,11 +599,16 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw, int slot_index = proto_data->cur_slot; if (slot_index < 0) - return; + return TRUE; - if (hw->slot_state[slot_index] == SLOTSTATE_OPEN_EMPTY) - hw->slot_state[slot_index] = SLOTSTATE_UPDATE; if (ev->code == ABS_MT_TRACKING_ID) { + if(hw->slot_state[slot_index] != SLOTSTATE_EMPTY && hw->slot_state[slot_index] != SLOTSTATE_OPEN_EMPTY) + { + // Happens when libevdev sends more than one open/close events in one SYN_REPORT packet. + // Must inject a SYN_REPORT for synaptics.c state machine + return FALSE; + } + if (ev->value >= 0) { hw->slot_state[slot_index] = SLOTSTATE_OPEN; proto_data->num_touches++; @@ -620,6 +633,9 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw, int map = proto_data->axis_map[ev->code - ABS_MT_TOUCH_MAJOR]; int last_val = valuator_mask_get(mask, map); + if (hw->slot_state[slot_index] == SLOTSTATE_OPEN_EMPTY) + hw->slot_state[slot_index] = SLOTSTATE_UPDATE; + valuator_mask_set(hw->mt_mask[slot_index], map, ev->value); if (EventTouchSlotPreviouslyOpen(priv, slot_index)) { if (ev->code == ABS_MT_POSITION_X) @@ -637,6 +653,8 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw, valuator_mask_set(mask, map, ev->value); } } + + return TRUE; } /** @@ -674,16 +692,34 @@ apply_st_scaling(struct eventcomm_proto_data *proto_data, int value, int axis) proto_data->st_to_mt_offset[axis]; } +static inline Bool +syn_report(InputInfoPtr pInfo, struct CommData *comm, struct SynapticsHwState *hwRet) +{ + struct SynapticsHwState *hw = comm->hwState; + SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; + struct eventcomm_proto_data *proto_data = priv->proto_data; + struct input_event *ev = &proto_data->last_ev; + + hw->numFingers = count_fingers(pInfo, comm); + if (proto_data->have_monotonic_clock) + hw->millis = 1000 * ev->time.tv_sec + ev->time.tv_usec / 1000; + else + hw->millis = GetTimeInMillis(); + + SynapticsCopyHwState(hwRet, hw); + return TRUE; +} + Bool EventReadHwState(InputInfoPtr pInfo, struct CommData *comm, struct SynapticsHwState *hwRet) { - struct input_event ev; Bool v; struct SynapticsHwState *hw = comm->hwState; SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; SynapticsParameters *para = &priv->synpara; struct eventcomm_proto_data *proto_data = priv->proto_data; + struct input_event *ev = &proto_data->last_ev; Bool sync_cumulative = FALSE; SynapticsResetTouchHwState(hw, FALSE); @@ -698,23 +734,19 @@ EventReadHwState(InputInfoPtr pInfo, sync_cumulative = TRUE; } - while (SynapticsReadEvent(pInfo, &ev)) { - switch (ev.type) { + while (proto_data->process_ev || SynapticsReadEvent(pInfo, ev)) { + proto_data->process_ev = FALSE; + + switch (ev->type) { case EV_SYN: - switch (ev.code) { + switch (ev->code) { case SYN_REPORT: - hw->numFingers = count_fingers(pInfo, comm); - if (proto_data->have_monotonic_clock) - hw->millis = 1000 * ev.time.tv_sec + ev.time.tv_usec / 1000; - else - hw->millis = GetTimeInMillis(); - SynapticsCopyHwState(hwRet, hw); - return TRUE; + return syn_report(pInfo, comm, hwRet); } break; case EV_KEY: - v = (ev.value ? TRUE : FALSE); - switch (ev.code) { + v = (ev->value ? TRUE : FALSE); + switch (ev->code) { case BTN_LEFT: hw->left = v; break; @@ -770,28 +802,32 @@ EventReadHwState(InputInfoPtr pInfo, } break; case EV_ABS: - if (ev.code < ABS_MT_SLOT) { - switch (ev.code) { + if (ev->code < ABS_MT_SLOT) { + switch (ev->code) { case ABS_X: - hw->x = apply_st_scaling(proto_data, ev.value, 0); + hw->x = apply_st_scaling(proto_data, ev->value, 0); if (sync_cumulative) hw->cumulative_dx = hw->x; break; case ABS_Y: - hw->y = apply_st_scaling(proto_data, ev.value, 1); + hw->y = apply_st_scaling(proto_data, ev->value, 1); if (sync_cumulative) hw->cumulative_dy = hw->y; break; case ABS_PRESSURE: - hw->z = ev.value; + hw->z = ev->value; break; case ABS_TOOL_WIDTH: - hw->fingerWidth = ev.value; + hw->fingerWidth = ev->value; break; } } else - EventProcessTouchEvent(pInfo, hw, &ev); + if(!EventProcessTouchEvent(pInfo, hw, ev)) + { + proto_data->process_ev = TRUE; + return syn_report(pInfo, comm, hwRet); + } break; } } -- 1.7.10.4