diff mbox series

HID parser: change usages table allocation to kvzalloc

Message ID 20230927105854.541910-1-marcin@helix.pl (mailing list archive)
State New
Delegated to: Jiri Kosina
Headers show
Series HID parser: change usages table allocation to kvzalloc | expand

Commit Message

Marcin Mikula Sept. 27, 2023, 10:58 a.m. UTC
There are devices which deliver buggy HID descriptors, repoting
Usage Maximum for particular Usage Page of max value (0xFFFF).

By decision of kernel HID subsystem developers such number will be limited
to arbitrary value of HID_MAX_USAGES (12288), and the following log will
be printed to warn about such condition:

"kernel: hid-generic 0005:057A:0087.001A: ignoring exceeding usage max"

but still the amount of memory allocated for HID_MAX_USAGES modified value
can be quite high as for kmalloc allocation.

On some systems with limited memory (seen in ARM based embedded system),
in high memory pressure condition an attempt to kmalloc() such value
can fail.
As a consequence this HID Usage Page will not parsed, so will not be
handled and the events will be ignored.

From the user perspective part of the input described with this Usage Page
simply will not work, which is a severe condition.

Change of kzalloc to kvzalloc makes sure that this allocation will
not fail.

Example of the kernel callstack when allocation fails for reference:

kernel: kworker/1:1: page allocation failure: order:7,
mode:0x40dc0(GFP_KERNEL|__GFP_COMP|__GFP_ZERO), nodemask=(null),cpuset=/,
mems_allowed=0

Workqueue: events uhid_device_add_worker
Call trace:
  dump_backtrace+0x0/0x1b4
  show_stack+0x24/0x30
  dump_stack+0xac/0x10c
  warn_alloc+0xd8/0x158
  __alloc_pages_slowpath+0x2e0/0x914
  __alloc_pages_nodemask+0x1b0/0x278
  kmalloc_order+0x30/0x7c
  kmalloc_order_trace+0x3c/0xd4
  __kmalloc+0x50/0x188
  hid_add_field+0x160/0x250
  hid_parser_main+0x220/0x25c
  hid_open_report+0x138/0x278
  hid_generic_probe+0x40/0x5c
  hid_device_probe+0x130/0x154
  really_probe+0x274/0x3f0
  driver_probe_device+0x118/0x128
  __device_attach_driver+0xc4/0x108
  bus_for_each_drv+0xa4/0xc8
  __device_attach+0xf4/0x17c
  device_initial_probe+0x24/0x30
  bus_probe_device+0x38/0x98
  device_add+0x4a0/0x578
  hid_add_device+0x100/0x294
  uhid_device_add_worker+0x28/0x70
  process_one_work+0x19c/0x294
  worker_thread+0x1e4/0x274
  kthread+0xdc/0xec
  ret_from_fork+0x10/0x18

Signed-off-by: Marcin Mikula <marcin@helix.pl>
---
 drivers/hid/hid-core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8992e3c1e769..0886868ee176 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -95,7 +95,7 @@  static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 		return NULL;
 	}
 
-	field = kzalloc((sizeof(struct hid_field) +
+	field = kvzalloc((sizeof(struct hid_field) +
 			 usages * sizeof(struct hid_usage) +
 			 3 * usages * sizeof(unsigned int)), GFP_KERNEL);
 	if (!field)
@@ -661,7 +661,7 @@  static void hid_free_report(struct hid_report *report)
 	kfree(report->field_entries);
 
 	for (n = 0; n < report->maxfield; n++)
-		kfree(report->field[n]);
+		kvfree(report->field[n]);
 	kfree(report);
 }