HID: core: do not upper bound the collection stack
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Fri, 13 Jul 2018 14:13:50 +0000 (16:13 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 17 Jul 2018 13:33:47 +0000 (15:33 +0200)
Looks like 4 was sufficient until now. However, the Surface Dial needs
a stack of 5 and simply fails at probing.
Dynamically add HID_COLLECTION_STACK_SIZE to the size of the stack if
we hit the upper bound.

Checkpatch complains about bare unsigned, so converting those to
'unsigned int' in struct hid_parser

Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-core.c
include/linux/hid.h

index 3942ee61bd1c17e57867a7d8e5f521b5f8eae9b8..5de6f18c9bf79fbb6ef147ce166566b5f1d15600 100644 (file)
@@ -128,9 +128,19 @@ static int open_collection(struct hid_parser *parser, unsigned type)
 
        usage = parser->local.usage[0];
 
-       if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
-               hid_err(parser->device, "collection stack overflow\n");
-               return -EINVAL;
+       if (parser->collection_stack_ptr == parser->collection_stack_size) {
+               unsigned int *collection_stack;
+               unsigned int new_size = parser->collection_stack_size +
+                                       HID_COLLECTION_STACK_SIZE;
+
+               collection_stack = krealloc(parser->collection_stack,
+                                           new_size * sizeof(unsigned int),
+                                           GFP_KERNEL);
+               if (!collection_stack)
+                       return -ENOMEM;
+
+               parser->collection_stack = collection_stack;
+               parser->collection_stack_size = new_size;
        }
 
        if (parser->device->maxcollection == parser->device->collection_size) {
@@ -840,6 +850,7 @@ static int hid_scan_report(struct hid_device *hid)
                break;
        }
 
+       kfree(parser->collection_stack);
        vfree(parser);
        return 0;
 }
index 2e4498d52a2fc8ef520a0b2d393cd2ba86831d30..aee281522c6db21941a915f2a5a1550e4575f8ad 100644 (file)
@@ -644,12 +644,13 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
 struct hid_parser {
        struct hid_global     global;
        struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
-       unsigned              global_stack_ptr;
+       unsigned int          global_stack_ptr;
        struct hid_local      local;
-       unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
-       unsigned              collection_stack_ptr;
+       unsigned int         *collection_stack;
+       unsigned int          collection_stack_ptr;
+       unsigned int          collection_stack_size;
        struct hid_device    *device;
-       unsigned              scan_flags;
+       unsigned int          scan_flags;
 };
 
 struct hid_class_descriptor {