[PATCH v3 6/8] HID: wacom: cleanup usage of 'driver_data'

"Pawel Zalewski (The Capable Hub)" <[email protected]>
Newsgroups org.kernel.vger.linux-input,org.kernel.vger.linux-kernel
Message-ID <20260727-mod-devicetable-hid_device_id-v3-6-980896ca283e@thegoodpenguin.co.uk>
This module is using the 'hid_device_id::driver_data' field
as a valid pointer to dereference. The hid subsystem allows
for injecting 'new_id' device via the command line. It follows
that it is more convenient to have 'driver_data' to be an integer
to allow the userspace to select a valid pointer via an index.

Lets enable this and store an index to the table of pointers
'wacom_features_table' instead, the access to this table is
bounded and checked at runtime via the 'wacom_features_table_index'
enum to avoid OOB dereferencing of objects.

The implementation relies heavily on the preprocessor - but
given the large amount of required entries (162) this is justified,
more robust and more resilient to user error than manual input.

Signed-off-by: Pawel Zalewski (The Capable Hub) <[email protected]>
---
 drivers/hid/wacom.h     | 177 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/hid/wacom_sys.c |  22 ++++--
 drivers/hid/wacom_wac.c |  25 +++++--
 3 files changed, 214 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
index 1deacb4568cb..115d0eb23277 100644
--- a/drivers/hid/wacom.h
+++ b/drivers/hid/wacom.h
@@ -228,6 +228,182 @@ static inline u32 wacom_rescale(u32 value, u32 in_max, u32 out_max)
 
 extern const struct hid_device_id wacom_ids[];
 
+/* This table lists all unique product IDs that are matched with
+ * a corresponging wacom_features_##prod struct. So any new product
+ * should be added to this table.
+ */
+#define HID_WACOM_PRODUCT_TABLE() \
+	table_entry(0x00) \
+	table_entry(0x03) \
+	table_entry(0x10) \
+	table_entry(0x11) \
+	table_entry(0x12) \
+	table_entry(0x13) \
+	table_entry(0x14) \
+	table_entry(0x15) \
+	table_entry(0x16) \
+	table_entry(0x17) \
+	table_entry(0x18) \
+	table_entry(0x19) \
+	table_entry(0x20) \
+	table_entry(0x21) \
+	table_entry(0x22) \
+	table_entry(0x23) \
+	table_entry(0x24) \
+	table_entry(0x26) \
+	table_entry(0x27) \
+	table_entry(0x28) \
+	table_entry(0x29) \
+	table_entry(0x2A) \
+	table_entry(0x30) \
+	table_entry(0x31) \
+	table_entry(0x32) \
+	table_entry(0x33) \
+	table_entry(0x34) \
+	table_entry(0x35) \
+	table_entry(0x37) \
+	table_entry(0x38) \
+	table_entry(0x39) \
+	table_entry(0x3F) \
+	table_entry(0x41) \
+	table_entry(0x42) \
+	table_entry(0x43) \
+	table_entry(0x44) \
+	table_entry(0x45) \
+	table_entry(0x47) \
+	table_entry(0x57) \
+	table_entry(0x59) \
+	table_entry(0x5B) \
+	table_entry(0x5D) \
+	table_entry(0x5E) \
+	table_entry(0x60) \
+	table_entry(0x61) \
+	table_entry(0x62) \
+	table_entry(0x63) \
+	table_entry(0x64) \
+	table_entry(0x65) \
+	table_entry(0x69) \
+	table_entry(0x6A) \
+	table_entry(0x6B) \
+	table_entry(0x81) \
+	table_entry(0x84) \
+	table_entry(0x90) \
+	table_entry(0x93) \
+	table_entry(0x94) \
+	table_entry(0x97) \
+	table_entry(0x9A) \
+	table_entry(0x9F) \
+	table_entry(0xB0) \
+	table_entry(0xB1) \
+	table_entry(0xB2) \
+	table_entry(0xB3) \
+	table_entry(0xB4) \
+	table_entry(0xB5) \
+	table_entry(0xB7) \
+	table_entry(0xB8) \
+	table_entry(0xB9) \
+	table_entry(0xBA) \
+	table_entry(0xBB) \
+	table_entry(0xBC) \
+	table_entry(0xBD) \
+	table_entry(0xC0) \
+	table_entry(0xC2) \
+	table_entry(0xC4) \
+	table_entry(0xC5) \
+	table_entry(0xC6) \
+	table_entry(0xC7) \
+	table_entry(0xCC) \
+	table_entry(0xCE) \
+	table_entry(0xD0) \
+	table_entry(0xD1) \
+	table_entry(0xD2) \
+	table_entry(0xD3) \
+	table_entry(0xD4) \
+	table_entry(0xD5) \
+	table_entry(0xD6) \
+	table_entry(0xD7) \
+	table_entry(0xD8) \
+	table_entry(0xDA) \
+	table_entry(0xDB) \
+	table_entry(0xDD) \
+	table_entry(0xDE) \
+	table_entry(0xDF) \
+	table_entry(0xE2) \
+	table_entry(0xE3) \
+	table_entry(0xE5) \
+	table_entry(0xE6) \
+	table_entry(0xEC) \
+	table_entry(0xED) \
+	table_entry(0xEF) \
+	table_entry(0xF0) \
+	table_entry(0xF4) \
+	table_entry(0xF6) \
+	table_entry(0xF8) \
+	table_entry(0xFA) \
+	table_entry(0xFB) \
+	table_entry(0x100) \
+	table_entry(0x101) \
+	table_entry(0x10D) \
+	table_entry(0x10E) \
+	table_entry(0x10F) \
+	table_entry(0x116) \
+	table_entry(0x12C) \
+	table_entry(0x300) \
+	table_entry(0x301) \
+	table_entry(0x302) \
+	table_entry(0x303) \
+	table_entry(0x304) \
+	table_entry(0x307) \
+	table_entry(0x309) \
+	table_entry(0x30A) \
+	table_entry(0x30C) \
+	table_entry(0x30E) \
+	table_entry(0x314) \
+	table_entry(0x315) \
+	table_entry(0x317) \
+	table_entry(0x318) \
+	table_entry(0x319) \
+	table_entry(0x323) \
+	table_entry(0x325) \
+	table_entry(0x326) \
+	table_entry(0x32A) \
+	table_entry(0x32B) \
+	table_entry(0x32C) \
+	table_entry(0x32F) \
+	table_entry(0x331) \
+	table_entry(0x333) \
+	table_entry(0x335) \
+	table_entry(0x336) \
+	table_entry(0x33B) \
+	table_entry(0x33C) \
+	table_entry(0x33D) \
+	table_entry(0x33E) \
+	table_entry(0x343) \
+	table_entry(0x360) \
+	table_entry(0x361) \
+	table_entry(0x377) \
+	table_entry(0x379) \
+	table_entry(0x37A) \
+	table_entry(0x37B) \
+	table_entry(0x393) \
+	table_entry(0x3c6) \
+	table_entry(0x3c8) \
+	table_entry(0x3dd) \
+	table_entry(0x4001) \
+	table_entry(0x4004) \
+	table_entry(0x5000) \
+	table_entry(0x5002) \
+	table_entry(0x6004) \
+	table_entry(HID_ANY_ID) \
+
+enum wacom_features_table_index {
+#define table_entry(product)	\
+	WACOM_FEATURE_TABLE_##product,
+	HID_WACOM_PRODUCT_TABLE()
+	NUM_OF_WACOM_FEATURES_IN_TABLE
+#undef table_entry
+};
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
 void wacom_setup_device_quirks(struct wacom *wacom);
 int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
@@ -249,4 +425,5 @@ struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur);
 int wacom_equivalent_usage(int usage);
 int wacom_initialize_leds(struct wacom *wacom);
 void wacom_idleprox_timeout(struct timer_list *list);
+const struct wacom_features *get_wacom_features(enum wacom_features_table_index index);
 #endif
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 0eafa483b7f7..834519751a5c 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -2559,8 +2559,13 @@ static void wacom_wireless_work(struct work_struct *work)
 		}
 
 		/* Stylus interface */
-		wacom_wac1->features =
-			*((struct wacom_features *)id->driver_data);
+		const struct wacom_features *features = get_wacom_features(id->driver_data);
+
+		if (!features) {
+			hid_err(wacom->hdev, "could not get wacom features.\n");
+			return;
+		}
+		wacom_wac1->features = *features;
 
 		wacom_wac1->pid = wacom_wac->pid;
 		hid_hw_stop(hdev1);
@@ -2572,8 +2577,7 @@ static void wacom_wireless_work(struct work_struct *work)
 		if (wacom_wac1->features.touch_max ||
 		    (wacom_wac1->features.type >= INTUOSHT &&
 		    wacom_wac1->features.type <= BAMBOO_PT)) {
-			wacom_wac2->features =
-				*((struct wacom_features *)id->driver_data);
+			wacom_wac2->features = *features;
 			wacom_wac2->pid = wacom_wac->pid;
 			hid_hw_stop(hdev2);
 			error = wacom_parse_and_register(wacom2, true);
@@ -2843,7 +2847,15 @@ static int wacom_probe(struct hid_device *hdev,
 	wacom->hdev = hdev;
 
 	wacom_wac = &wacom->wacom_wac;
-	wacom_wac->features = *((struct wacom_features *)id->driver_data);
+
+	const struct wacom_features *id_features = get_wacom_features(id->driver_data);
+
+	if (!id_features) {
+		hid_err(wacom->hdev, "could not get wacom id_features.\n");
+		return -EINVAL;
+	}
+	wacom_wac->features = *id_features;
+
 	features = &wacom_wac->features;
 
 	if (features->check_for_hid_type && features->hid_type != hdev->type)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index da1f0ea85625..d0a864d52509 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -4945,25 +4945,40 @@ static const struct wacom_features wacom_features_HID_ANY_ID =
 static const struct wacom_features wacom_features_0x94 =
 	{ "Wacom Bootloader", .type = BOOTLOADER };
 
+static const struct wacom_features *wacom_features_table[] = {
+#define table_entry(product)				\
+	[WACOM_FEATURE_TABLE_##product] = &wacom_features_##product,
+	HID_WACOM_PRODUCT_TABLE()
+#undef table_entry
+};
+
+const struct wacom_features *get_wacom_features(enum wacom_features_table_index index)
+{
+	if (index >= NUM_OF_WACOM_FEATURES_IN_TABLE)
+		return NULL;
+
+	return wacom_features_table[index];
+}
+
 #define USB_DEVICE_WACOM(prod)						\
 	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+	.driver_data = WACOM_FEATURE_TABLE_##prod
 
 #define BT_DEVICE_WACOM(prod)						\
 	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+	.driver_data = WACOM_FEATURE_TABLE_##prod
 
 #define I2C_DEVICE_WACOM(prod)						\
 	HID_DEVICE(BUS_I2C, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+	.driver_data = WACOM_FEATURE_TABLE_##prod
 
 #define PCI_DEVICE_WACOM(prod)						\
 	HID_DEVICE(BUS_PCI, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+	.driver_data = WACOM_FEATURE_TABLE_##prod
 
 #define USB_DEVICE_LENOVO(prod)					\
 	HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),			\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+	.driver_data = WACOM_FEATURE_TABLE_##prod
 
 const struct hid_device_id wacom_ids[] = {
 	{ USB_DEVICE_WACOM(0x00) },

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.