mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] HID: roccat: bound device-supplied profile index
@ 2026-06-18  3:00 Michael Bommarito
  2026-06-18  3:00 ` [PATCH 1/2] " Michael Bommarito
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Michael Bommarito @ 2026-06-18  3:00 UTC (permalink / raw)
  To: Stefan Achatz, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel

The Roccat Kone driver uses an 8-bit value taken straight from a USB HID
interrupt report as an index into a fixed 5-element profiles[] array,
without any range check. A malicious or counterfeit device that claims
the Roccat Kone VID/PID can send a "switch profile" report with an
out-of-range value and make the driver read out of bounds; the same
unbounded index is also reachable at probe time from a device-supplied
startup_profile field. The read result is stored in actual_dpi and
exposed to user space through the actual_dpi sysfs attribute.

Michael Bommarito (2):
  HID: roccat: bound device-supplied profile index
  HID: roccat: add KUnit test for kone profile-index bounds

 drivers/hid/Kconfig           |  9 +++++
 drivers/hid/hid-roccat-kone.c | 65 +++++++++++++++++++++++++++++++++--
 2 files changed, 72 insertions(+), 2 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] HID: roccat: bound device-supplied profile index
  2026-06-18  3:00 [PATCH 0/2] HID: roccat: bound device-supplied profile index Michael Bommarito
@ 2026-06-18  3:00 ` Michael Bommarito
  2026-06-18  3:00 ` [PATCH 2/2] HID: roccat: add KUnit test for kone profile-index bounds Michael Bommarito
  2026-06-29  9:16 ` [PATCH 0/2] HID: roccat: bound device-supplied profile index Jiri Kosina
  2 siblings, 0 replies; 4+ messages in thread
From: Michael Bommarito @ 2026-06-18  3:00 UTC (permalink / raw)
  To: Stefan Achatz, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel

kone_keep_values_up_to_date() and kone_profile_activated() use an
8-bit, device-supplied profile value as an index into the 5-element
kone->profiles[] array without a range check. A malicious USB device
claiming the Roccat Kone id can send a switch-profile event (or a
startup_profile read at probe) with an out-of-range value and make the
driver read out of bounds; the result is exposed via the actual_dpi
sysfs attribute.

Reject out-of-range indices in both paths.

This was found with static analysis and confirmed with the KUnit test
added in the following patch (KASAN: slab-out-of-bounds).

Fixes: 14bf62cde7942 ("HID: add driver for Roccat Kone gaming mouse")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 drivers/hid/hid-roccat-kone.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 58654cf78f0df..17495fcc8b7da 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -36,6 +36,8 @@ static uint profile_numbers[5] = {0, 1, 2, 3, 4};
 
 static void kone_profile_activated(struct kone_device *kone, uint new_profile)
 {
+	if (new_profile < 1 || new_profile > ARRAY_SIZE(kone->profiles))
+		new_profile = 1;
 	kone->actual_profile = new_profile;
 	kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi;
 }
@@ -793,8 +795,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
 {
 	switch (event->event) {
 	case kone_mouse_event_switch_profile:
-		kone->actual_dpi = kone->profiles[event->value - 1].
-				startup_dpi;
+		if (event->value >= 1 &&
+		    event->value <= ARRAY_SIZE(kone->profiles))
+			kone->actual_dpi =
+				kone->profiles[event->value - 1].startup_dpi;
 		fallthrough;
 	case kone_mouse_event_osd_profile:
 		kone->actual_profile = event->value;
-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/2] HID: roccat: add KUnit test for kone profile-index bounds
  2026-06-18  3:00 [PATCH 0/2] HID: roccat: bound device-supplied profile index Michael Bommarito
  2026-06-18  3:00 ` [PATCH 1/2] " Michael Bommarito
@ 2026-06-18  3:00 ` Michael Bommarito
  2026-06-29  9:16 ` [PATCH 0/2] HID: roccat: bound device-supplied profile index Jiri Kosina
  2 siblings, 0 replies; 4+ messages in thread
From: Michael Bommarito @ 2026-06-18  3:00 UTC (permalink / raw)
  To: Stefan Achatz, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel

Drive kone_keep_values_up_to_date() with a crafted switch-profile event;
an out-of-range value reads past profiles[] (KASAN slab-out-of-bounds on
an unpatched tree). A benign control with an in-range value exercises the
same path. The test object is sized to end at profiles[] so the over-read
lands in the KASAN redzone.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 drivers/hid/Kconfig           |  9 ++++++
 drivers/hid/hid-roccat-kone.c | 57 +++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ff2f580b660ba..3c6bc918aeb54 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1057,6 +1057,15 @@ config HID_ROCCAT
 	Say Y here if you have a Roccat mouse or keyboard and want
 	support for its special functionalities.
 
+config HID_ROCCAT_KONE_KUNIT_TEST
+	bool "KUnit tests for the Roccat Kone driver" if !KUNIT_ALL_TESTS
+	depends on HID_ROCCAT=y && KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  Enable the KUnit regression tests for the Roccat Kone driver,
+	  covering bounds checking of device-supplied profile indices.
+	  If unsure, say N.
+
 config HID_SAITEK
 	tristate "Saitek (Mad Catz) non-fully HID-compliant devices"
 	help
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 17495fcc8b7da..3dae9eaa0b6f4 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -919,3 +919,60 @@ module_exit(kone_exit);
 MODULE_AUTHOR("Stefan Achatz");
 MODULE_DESCRIPTION("USB Roccat Kone driver");
 MODULE_LICENSE("GPL v2");
+
+#if IS_ENABLED(CONFIG_HID_ROCCAT_KONE_KUNIT_TEST)
+#include <kunit/test.h>
+
+/*
+ * Regression test for the out-of-bounds read in
+ * kone_keep_values_up_to_date(): a malicious USB device sends a
+ * "switch profile" HID event (event == kone_mouse_event_switch_profile)
+ * with an attacker-chosen value in 0..255, which is used unbounded as
+ * profiles[value - 1].  On an unpatched kernel the attack case triggers a
+ * KASAN slab-out-of-bounds read; the fix must leave actual_dpi unchanged.
+ */
+static void kone_profile_index_oob_test(struct kunit *test)
+{
+	struct kone_device *kone;
+	struct kone_mouse_event ev = {};
+	/*
+	 * Allocate only up to the end of profiles[] so that any index past
+	 * the 5-element array is IMMEDIATELY out of bounds and lands in the
+	 * KASAN redzone (a far over-read would hit unrelated valid memory and
+	 * escape KASAN).
+	 */
+	size_t sz = offsetof(struct kone_device, profiles) +
+		    sizeof(kone->profiles);
+
+	kone = kunit_kzalloc(test, sz, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, kone);
+	kone->profiles[0].startup_dpi = 0x42;
+
+	/* benign control: a valid in-range value drives the SAME path and
+	 * must succeed (proves the trigger reaches the real code).
+	 */
+	ev.event = kone_mouse_event_switch_profile;
+	ev.value = 1;
+	kone_keep_values_up_to_date(kone, &ev);
+	KUNIT_EXPECT_EQ(test, kone->actual_dpi, 0x42);
+
+	/* attack: value == ARRAY_SIZE(profiles) + 1 reads profiles[5], one
+	 * element past the array end -> KASAN slab-out-of-bounds read on an
+	 * unpatched kernel. The fix must reject it (actual_dpi unchanged).
+	 */
+	ev.value = ARRAY_SIZE(kone->profiles) + 1;
+	kone_keep_values_up_to_date(kone, &ev);
+	KUNIT_EXPECT_EQ(test, kone->actual_dpi, 0x42);
+}
+
+static struct kunit_case kone_test_cases[] = {
+	KUNIT_CASE(kone_profile_index_oob_test),
+	{}
+};
+
+static struct kunit_suite kone_test_suite = {
+	.name = "hid-roccat-kone",
+	.test_cases = kone_test_cases,
+};
+kunit_test_suite(kone_test_suite);
+#endif /* CONFIG_HID_ROCCAT_KONE_KUNIT_TEST */
-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] HID: roccat: bound device-supplied profile index
  2026-06-18  3:00 [PATCH 0/2] HID: roccat: bound device-supplied profile index Michael Bommarito
  2026-06-18  3:00 ` [PATCH 1/2] " Michael Bommarito
  2026-06-18  3:00 ` [PATCH 2/2] HID: roccat: add KUnit test for kone profile-index bounds Michael Bommarito
@ 2026-06-29  9:16 ` Jiri Kosina
  2 siblings, 0 replies; 4+ messages in thread
From: Jiri Kosina @ 2026-06-29  9:16 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Stefan Achatz, Benjamin Tissoires, linux-input, linux-kernel

On Wed, 17 Jun 2026, Michael Bommarito wrote:

> The Roccat Kone driver uses an 8-bit value taken straight from a USB HID
> interrupt report as an index into a fixed 5-element profiles[] array,
> without any range check. A malicious or counterfeit device that claims
> the Roccat Kone VID/PID can send a "switch profile" report with an
> out-of-range value and make the driver read out of bounds; the same
> unbounded index is also reachable at probe time from a device-supplied
> startup_profile field. The read result is stored in actual_dpi and
> exposed to user space through the actual_dpi sysfs attribute.
> 
> Michael Bommarito (2):
>   HID: roccat: bound device-supplied profile index
>   HID: roccat: add KUnit test for kone profile-index bounds

Applied, thanks.

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-29  9:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-18  3:00 [PATCH 0/2] HID: roccat: bound device-supplied profile index Michael Bommarito
2026-06-18  3:00 ` [PATCH 1/2] " Michael Bommarito
2026-06-18  3:00 ` [PATCH 2/2] HID: roccat: add KUnit test for kone profile-index bounds Michael Bommarito
2026-06-29  9:16 ` [PATCH 0/2] HID: roccat: bound device-supplied profile index Jiri Kosina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®