From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BEF323EDAC1 for ; Thu, 23 Jul 2026 22:42:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.42 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784846550; cv=none; b=HkkTYhMy5DQRLhDNoUpegoretr2m4V0d6dfGYY2V86gUxK9vK69NCIkYM5u77hsH2Dszjs/Sjj7BOOd4BTycb947TM18sLE2hTQbGBMkTxWYFyY28/Mj5GCjGUCeahFsJOFvzEx4+KGSZX4oHEh84cvO0Cdhe2m84B4AXVZvero= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784846550; c=relaxed/simple; bh=8NVtpDOwjU7udwxECy9jxjiPQv82i59N1FgCx5vcIrk=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=EWB84w3KJQ3u4PUwHsKTEoA4nt6sxJzmDGAW1UD1f85w+GGvHqwwAJRN5IJY2KOWvROfiaaTdCfhgAzVTPbZIA6t8AuqeAmMTVP8R8GfFGoJVIoqHWjJ/sRYWRXLB90kjOcvn/oWoAe2eW7f9y/5N4SI1+723jlk6PQ7h2ZtCzA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=OPT/k2FK; arc=none smtp.client-ip=209.85.218.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OPT/k2FK" Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-c15f020a223so159656066b.1 for ; Thu, 23 Jul 2026 15:42:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784846547; x=1785451347; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=vlojMWIujU/Cv7htl//acVMDx5/x7mtDVl69pcel8kw=; b=OPT/k2FKVn0nbyUG2fsPVUqnlBLYu7DoEOglF7JSaxn66lcDPmmHMO/apsq0s2EKIA tnw++RvuMOlK7mTEA7f9UCtsoNwwK/8Tdy4GyNBIYZa+mcW+hMTY1VkfcsAp5sT7S436 Jkn+tbXX1AncgxmcHo3T1VW2fFMqlTZDNzdjsHYX4B/4r/Om5H/zEePbpkhxyVH25KE0 MLQY+ELRbuoikCULx/8PUymliWxNHrl4ZJWfTscvMlKlPMiZIyNLNuZCgKmnxs2sU7+B r6T8u9YqV/mpiOkMWgCBMIWg30x6kgt3QEbp52qC1WvdUwJfkFje0kcPINtrbQJVhf7u KZPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784846547; x=1785451347; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=vlojMWIujU/Cv7htl//acVMDx5/x7mtDVl69pcel8kw=; b=YsX81oLAdwfdwne1uFv2l/0B6tt/+C4A3YGxyWIR2hMSVj85YdZhgg6lnie/X5tUYk xvUkPMF/9H12Uhqcuhkbst3w63x9JC16E0lm9911HgxsuJlFFJMNhlgpKEGwCDvSaUZd LDgWnmJgMYRofRdeqkShEaR4AtjSNHUqhAbCzialya9qrurMSUGBAkB91HcxPHqRL98F pdHj7chxcNgvodNmhLMfUQvSZ6hCJGf1VfePxjpyf8K9Rh6cD8Sl9saVhBn/zliRas9E rFVOnOUVVmm15jwbTb/nQYLHcPHGikIEQep1zUTxED/XJ3Hx/CYXRpK7ryRCQapmFfH9 rb/w== X-Forwarded-Encrypted: i=1; AHgh+RrwWhU9Kp3YDC4mEw41sXMLwHokY6RmVzV67KqFe3kVFnVLnpQ49E9K+WVPQdJTYzHXIAvJr7XdhxsQXKE=@vger.kernel.org X-Gm-Message-State: AOJu0YxwM6Ly9PlXK0MXi1q1oQZU8qfbh/giwQrZ+KCkiaP7bki1v2VT fzGG0BJw157zF1g1pUqwZCtqhT3akz0BPjGmAivS4RjzaTHjChzqikjJ X-Gm-Gg: AR+sD13SPTlS8jUly1DtbzCqhLYN/TOdPWRqC77UoSgOhbuf8DMtCwARq8PXswWalRV 8D0uzkOl1fJrUFs8DJP7MWCoO0GuIf5OoqmuJ4/C+UU6v8QvGkJ1pASHRpzlaQ7cp0kn5OFmrgV nY+LTfhU/Owx6NWESMvsCMWEROuLAIl34PWhE5vQAeC2KXE5JpQgSEPjf7QwaL9dsd7rjwUje5O zxxx/r+pbDSpOBmM+ZmVWrPfld+fm9EOEt43jxFgCPlm3JUf78whgqteneFttiL3weyp/56fEbI EQRAk8sIqziD7ieAUY3czJYSrgDmW5V2Zy7XguTxDxeBNeE6dXTyjRkthUj9QQRJHeMpDKKO+ND AUeGsBhC41H3hq5xG/ERWA7jKs5M8jWh7iBUyecPhQ+KaEnBv1c24PQaS5fcwh3TOhBiwfg== X-Received: by 2002:a17:907:3f09:b0:c15:d068:9160 with SMTP id a640c23a62f3a-c1c50d1c8bfmr208935166b.31.1784846546715; Thu, 23 Jul 2026 15:42:26 -0700 (PDT) Received: from beelink.. ([186.247.163.143]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c1c32f13123sm276428466b.59.2026.07.23.15.42.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jul 2026 15:42:25 -0700 (PDT) From: Your Name X-Google-Original-From: Your Name To: linux-input@vger.kernel.org Cc: jikos@kernel.org, bentiss@kernel.org, linux-kernel@vger.kernel.org, Aldo Ariel Panzardo , stable@vger.kernel.org Subject: [PATCH] HID: multitouch: bound the slot index before touching mt_io_flags Date: Thu, 23 Jul 2026 19:42:11 -0300 Message-ID: <20260723224211.613112-1-you@example.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Aldo Ariel Panzardo td->mt_io_flags is a single unsigned long. Its first MT_IO_SLOTS_BITS bits track per-slot state, read back through MT_IO_SLOTS_MASK, while bit 32 holds MT_IO_FLAGS_RUNNING, which the report path and the sticky-finger timer take and release with test_and_set_bit_lock() and clear_bit_unlock(). set_bit()/clear_bit() are called on that word with the slot number as the bit index: set_bit(slotnum, &td->mt_io_flags); slotnum is bounded only by td->maxcontacts, which is taken from the HID CONTACTMAX feature value and can reach MT_MAX_MAXCONTACT (250). Two things go wrong once a device reports a slot number of 8 or more: - a slot number of 32 sets MT_IO_FLAGS_RUNNING from the data path. mt_expired_timeout() then finds the flag already set and returns early, so sticky fingers are never released, and the clear_bit_unlock() in the other path drops a lock it does not hold. Several in-tree classes declare .maxcontacts of 40 and 60, so this is reachable with ordinary hardware. - a slot number of BITS_PER_LONG or more writes past the end of the word altogether, corrupting the struct mt_device fields that follow it. The same unchecked index is used in mt_release_pending_palms(), where slotnum comes from a for_each_set_bit() bounded by td->maxcontacts, and in mt_release_contacts(), where it is bounded by mt->num_slots. Bound the index to the reserved slot range in one place and use that for every set_bit()/clear_bit() on mt_io_flags. Dropping the out-of-range slots is not a functional change: both readers of the slot state mask with MT_IO_SLOTS_MASK, so bits at or above MT_IO_SLOTS_BITS were never observable to begin with. Also correct the comment on the field, which claimed that eight bits were sufficient because at most 250 slots are supported. Fixes: 46f781e0d151 ("HID: multitouch: fix sticky fingers") Cc: stable@vger.kernel.org Signed-off-by: Aldo Ariel Panzardo --- drivers/hid/hid-multitouch.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 0495152091e3..463eab9f73cd 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -98,6 +98,7 @@ enum report_mode { }; #define MT_IO_SLOTS_MASK GENMASK(7, 0) /* reserve first 8 bits for slot tracking */ +#define MT_IO_SLOTS_BITS 8 /* bits covered by MT_IO_SLOTS_MASK */ #define MT_IO_FLAGS_RUNNING 32 static const bool mtrue = true; /* default for true */ @@ -175,9 +176,10 @@ struct mt_device { struct hid_haptic_device *haptic; /* haptic related configuration */ struct hid_device *hdev; /* hid_device we're attached to */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_RUNNING) - * first 8 bits are reserved for keeping the slot - * states, this is fine because we only support up - * to 250 slots (MT_MAX_MAXCONTACT) + * the first MT_IO_SLOTS_BITS bits are reserved + * for keeping the slot states; higher slot + * numbers are not tracked here, see + * mt_io_slot_set() */ __u8 inputmode_value; /* InputMode HID feature value */ __u8 maxcontacts; @@ -1027,6 +1029,25 @@ static int mt_compute_slot(struct mt_dev return input_mt_get_slot_by_key(input, *slot->contactid); } +/* + * Only the first MT_IO_SLOTS_BITS bits of mt_io_flags track slot state; the + * rest of the word holds unrelated flags such as MT_IO_FLAGS_RUNNING. Slot + * numbers are bounded by td->maxcontacts, which is taken from the HID + * CONTACTMAX feature and can be much larger, so the index has to be checked + * before touching the word. + */ +static void mt_io_slot_set(struct mt_device *td, int slotnum) +{ + if (slotnum < MT_IO_SLOTS_BITS) + set_bit(slotnum, &td->mt_io_flags); +} + +static void mt_io_slot_clear(struct mt_device *td, int slotnum) +{ + if (slotnum < MT_IO_SLOTS_BITS) + clear_bit(slotnum, &td->mt_io_flags); +} + static void mt_release_pending_palms(struct mt_device *td, struct mt_application *app, struct input_dev *input) @@ -1036,7 +1057,7 @@ static void mt_release_pending_palms(str for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) { clear_bit(slotnum, app->pending_palm_slots); - clear_bit(slotnum, &td->mt_io_flags); + mt_io_slot_clear(td, slotnum); input_mt_slot(input, slotnum); input_mt_report_slot_inactive(input); @@ -1247,9 +1268,9 @@ static int mt_process_slot(struct mt_dev input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); - set_bit(slotnum, &td->mt_io_flags); + mt_io_slot_set(td, slotnum); } else { - clear_bit(slotnum, &td->mt_io_flags); + mt_io_slot_clear(td, slotnum); } return 0; @@ -2062,7 +2083,7 @@ static void mt_release_contacts(struct h for (i = 0; i < mt->num_slots; i++) { input_mt_slot(input_dev, i); input_mt_report_slot_inactive(input_dev); - clear_bit(i, &td->mt_io_flags); + mt_io_slot_clear(td, i); } input_mt_sync_frame(input_dev); input_sync(input_dev); -- 2.43.0