From nobody Mon Sep 28 11:39:33 2026 Received: from mail-pf1-f171.google.com (mail-pf1-f171.google.com [209.85.210.171]) (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 C89513C063A for ; Sat, 22 Aug 2026 12:10:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787400617; cv=none; b=ajdGYiBhadBjChrmvdzMBSJD+DV5K5T18mUQO/IrP9oDD4itU6uKT0GS2tUY5u8khERtGQvaxzvlNALfd+L66BuOguuF6qICzli6NK6rX1/OAJHtyau3lCoceeU7VCr3e46vPM2vDCg69Qkj8IS00mOsSSCfGMYiNv6eDeKTjVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787400617; c=relaxed/simple; bh=Vr5HGOvmvPpkjWgDtThY64AqnPg00tx71QkxFIVq8XI=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=rOuD+T/g/MLgipAzzdi/gWdKQWAfr3HQdQiOKcQWRSXNyb1aY7QKNH/yNHAzEJzEK19a1Bwur5aBo41bkzjlvQGeOoewjdt/wh/3CAHO/wHeJPk8AbkEcTcpzdqhafLQVCV1khN0vPVBAT/XxDTYOIEbz+ytsb8WCT62P56dntk= 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=sabii66r; arc=none smtp.client-ip=209.85.210.171 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="sabii66r" Received: by mail-pf1-f171.google.com with SMTP id d2e1a72fcca58-84e0688b7e8so1356302b3a.1 for ; Sat, 22 Aug 2026 05:10:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787400615; x=1788005415; 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=HwQOW24aYq8g+uW7VI9Ls6LuehzpGekB5XJ+3F7qiHM=; b=sabii66r+sbIe/u2lt4lIAKlZm4j/Ny9GfsYlmqRnyamL1CFnZupXqGmc3iDKVmBCW Dpzu8TCbhMAfF5omYPxEwnb1cIInTEq9EhL9Y/8HV6D6kx9+TGo+e/HJll5I/AU9XDzQ Yn3A1rxdlMOkklvsjuCJCoQlfbNHDX/8HZY9bu/ZBlj7SnNTWmtXsLU8bOnjgE1fqpn2 4zN7NpH4WfXkvpKhZYS+r8dTI3b5IIdAGTKp6i0Fy9sAnRthtlnHEFHheWNQwLLP44RL hvmAfQZplAncygZYYdzZSP8EbYlyd2kgyxd4+5XeBcp0Sm0V6ZHfpCnwgL+5Sn3PVov8 fCDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787400615; x=1788005415; 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=HwQOW24aYq8g+uW7VI9Ls6LuehzpGekB5XJ+3F7qiHM=; b=XOlWp87sqBU9ae66o3dp/0DOGDPxTNDiwO3nf6RYHq2SgdUCm147Re5wHYEJANbi2P a03nHdVpZRq3jOythmGgxWkXbZCpYwqKvf9dyLxmjXLIAkTLq3HumC4esX/ZiWa8WfMt jLJgdrm8g4HGTL6J4aALa1cXClfnb7rbFgFG+EPO3mIPe3H2jCGzcC9w+kBWKjCUHpkL Yv+T/oyu4rrB5+M45Y9gLhFGY2PVt70GC8v4j+p1xlUHEHPGPNERcHLxL90Vvdfi37ya hDuonRm0wABjXYdNK1cdC+FzrcRTUvAWdiWK3U2+/XOLoAzLOMSAck16tYdgtJ47sU9x tgMw== X-Forwarded-Encrypted: i=1; AHgh+RqtYaNFAX/Nouf30zQu1+l3l+815fekrOwWA3LITGZzgTeYEzXaFohm6qUrWO4W9IJuLO9SfmLAFybjcA8=@vger.kernel.org X-Gm-Message-State: AFuF++lyCBg1Xdy61cXx8wNy3c5A+6q5SXNHYRtjTsxS2s8DPCLyHQMT Qo3RO3zEGHNaQjNHzk/s/NKF9d9+mMLFGlCgB4cbkimF0D9F66vM7QLW X-Gm-Gg: AR+sD105xs3wWPbTqWCSXFH44pLMdQCBgGQQ0D7lLaEYL4SKNW8be2X9QWTTqCYyjhZ zw0oU8as7RRoNjTlH5kTPWNT3bP7eetyUu7jbaqtpiOGd+9g47Lw610T0FWmcRDkD4o4D2LKrM3 Kw+lA+KRDe5+U+imUKZTNB6mTsK6jy8fXmvE5ywIvVxwoeYSiYPHGodrvCEaIlyz6CQokvHkNc0 2nwH6iIWaTNBWKNoUiaL3WVmGgMO0dIxBXE+UcgW82IRy92OTJoG1A5XHxW1ubBu8gPKCaXbUCq tLkp7d/JWZCW+z9WZHwz8vD/jMaSYN6+axu+LA5bF0Txos7Ly/Ews1m9FTfOL82mpiZmuKQ0orQ Z29oIV9hFpYAKW4GdRFRnSZrOaqijkADmndqBLi1NvgC8TBfPWvwfJAEcsdcmPjan+ssm/p1tOt 0B3LKhpjD9M86wLuV5TN3BDcnLAUidqxISlA9BGxxiwmcjNy6haU4plENqP9dXVU7MFysKFqHk7 b+RljSOdLVE3rxCUe8HBqtci5f5475pZZ8V2bT2d+w6Jpi2PqdhS4MIAGVp8wiceohJKmLIsO4Y PYA01ypmwt8i99fNkLquOYLo X-Received: by 2002:a05:6a00:194b:b0:851:8012:c38b with SMTP id d2e1a72fcca58-8520ba23894mr7689217b3a.10.1787400615010; Sat, 22 Aug 2026 05:10:15 -0700 (PDT) Received: from LAPTOP-UUUVNN1I.localdomain (bb119-74-6-224.singnet.com.sg. [119.74.6.224]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-8520f03b243sm522696b3a.31.2026.08.22.05.10.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Aug 2026 05:10:14 -0700 (PDT) From: Wei Jie Law <98lawweijie@gmail.com> To: Jiri Kosina , Benjamin Tissoires , Andrew Duggan Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] HID: rmi: fix OOB access with undersized RMI reports Date: Sat, 22 Aug 2026 20:10:07 +0800 Message-ID: <20260822121007.153988-1-98lawweijie@gmail.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: quoted-printable Content-Type: text/plain; charset="utf-8" The hid-rmi driver sizes its writeReport/readReport buffer purely from the report descriptor supplied by the device, with no minimum bound: data->input_report_size =3D hid_report_len(input_report); data->output_report_size =3D hid_report_len(output_report); alloc_size =3D data->output_report_size + data->input_report_size; data->writeReport =3D devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); but then writes fixed offsets into that buffer without validating the sizes. A device declaring a 1-byte output report (0x09) and a 1-byte input report (0x0c) makes hid_report_len() return 2 for each, so alloc_size is 4, and rmi_set_page() -- reached unconditionally at probe time through rmi_input_configured() -- writes writeReport[4], one byte past the allocation. rmi_hid_read_block() writes writeReport[0..5] in the same way, and rmi_hid_write_block() copies an unbounded len to &writeReport[4]. The read path has the mirror image of the problem: the copy length comes from readReport[1], which is filled in from the device's response and can be up to 255, and the copy starts at &readReport[2] without any regard for input_report_size, so it runs past the allocation and into adjacent slab objects. Those bytes become the register values the RMI core acts on; they are printed to the kernel log as the product id by rmi_f01_probe(), and they are sent back to the device as the interrupt mask by rmi_driver_set_irq_bits(), so an undersized report descriptor leaks heap contents both to userspace and to the device itself. Reject reports that are too small at probe time, where the driver needs 6 output bytes for the write reports it builds and 3 input bytes for the read handshake, and clamp the write and the read copy to the report sizes the device declared. A write longer than the output report was already overrunning the buffer, so rejecting it cannot regress a device that used to work. Verified on v6.12.104, whose hid-rmi.c is identical to mainline here, with a UHID reproducer and with an emulated USB device (raw-gadget): a breakpoint on rmi_set_page() shows the store to writeReport[4] executing with alloc_size =3D=3D 4, and after the change probe stops with "rmi reports too small (out=3D2 in=3D2)". With a larger descriptor the read path returns kernel heap bytes, observed both in the product id printed by rmi_f01_probe() and in the interrupt mask written back to the emulated device. Fixes: 9fb6bf02e3ad ("HID: rmi: introduce RMI driver for Synaptics touchpad= s") Cc: stable@vger.kernel.org Signed-off-by: Wei Jie Law <98lawweijie@gmail.com> --- The reproducer is available on request. Compile-tested on bd5f485f3f02, x86_64 defconfig + CONFIG_HID_RMI=3Dy. drivers/hid/hid-rmi.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index d4af17fdba46..a0780087d413 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -235,7 +235,8 @@ static int rmi_hid_read_block(struct rmi_transport_dev = *xport, u16 addr, break; } =20 - read_input_count =3D data->readReport[1]; + read_input_count =3D min_t(int, data->readReport[1], + data->input_report_size - 2); memcpy(buf + bytes_read, &data->readReport[2], min(read_input_count, bytes_needed)); =20 @@ -271,6 +272,11 @@ static int rmi_hid_write_block(struct rmi_transport_de= v *xport, u16 addr, goto exit; } =20 + if (len > data->output_report_size - 4) { + ret =3D -EINVAL; + goto exit; + } + data->writeReport[0] =3D RMI_WRITE_REPORT_ID; data->writeReport[1] =3D len; data->writeReport[2] =3D addr & 0xFF; @@ -696,6 +702,17 @@ static int rmi_probe(struct hid_device *hdev, const st= ruct hid_device_id *id) =20 data->output_report_size =3D hid_report_len(output_report); =20 + /* + * The write reports built by this driver occupy 6 bytes and the read + * handshake looks at the first 3 bytes of an input report, so refuse + * to drive a device whose reports cannot hold them. + */ + if (data->output_report_size < 6 || data->input_report_size < 3) { + hid_err(hdev, "rmi reports too small (out=3D%u in=3D%u)\n", + data->output_report_size, data->input_report_size); + goto start; + } + data->device_flags |=3D RMI_DEVICE; alloc_size =3D data->output_report_size + data->input_report_size; =20 base-commit: bd5f485f3f026225b86573e559af0b7254ef4184 --=20 2.43.0