@@ -168,12 +168,12 @@ static int open_collection(struct hid_parser *parser, unsigned type)
parser->device->maxcollection;
collection = parser->device->collection +
- parser->device->maxcollection++;
+ parser->device->maxcollection;
collection->type = type;
collection->usage = usage;
collection->level = parser->collection_stack_ptr - 1;
collection->parent = parser->active_collection;
- parser->active_collection = collection;
+ parser->active_collection = parser->device->maxcollection++;
if (type == HID_COLLECTION_APPLICATION)
parser->device->maxapplication++;
@@ -192,8 +192,9 @@ static int close_collection(struct hid_parser *parser)
return -EINVAL;
}
parser->collection_stack_ptr--;
- if (parser->active_collection)
- parser->active_collection = parser->active_collection->parent;
+ if (parser->active_collection != UINT_MAX)
+ parser->active_collection =
+ parser->device->collection[parser->active_collection].parent;
return 0;
}
@@ -819,6 +820,7 @@ static int hid_scan_report(struct hid_device *hid)
return -ENOMEM;
parser->device = hid;
+ parser->active_collection = UINT_MAX;
hid->group = HID_GROUP_GENERIC;
/*
@@ -1006,8 +1008,10 @@ static void hid_apply_multiplier_to_field(struct hid_device *hid,
usage = &field->usage[i];
collection = &hid->collection[usage->collection_index];
- while (collection && collection != multiplier_collection)
- collection = collection->parent;
+ while (collection && collection != multiplier_collection) {
+ collection = (collection->parent == UINT_MAX) ? NULL :
+ &hid->collection[collection->parent];
+ }
if (collection || multiplier_collection == NULL)
usage->resolution_multiplier = effective_multiplier;
@@ -1045,8 +1049,11 @@ static void hid_apply_multiplier(struct hid_device *hid,
*/
multiplier_collection = &hid->collection[multiplier->usage->collection_index];
while (multiplier_collection &&
- multiplier_collection->type != HID_COLLECTION_LOGICAL)
- multiplier_collection = multiplier_collection->parent;
+ multiplier_collection->type != HID_COLLECTION_LOGICAL) {
+ multiplier_collection =
+ (multiplier_collection->parent == UINT_MAX) ? NULL :
+ &hid->collection[multiplier_collection->parent];
+ }
effective_multiplier = hid_calculate_multiplier(hid, multiplier);
@@ -1170,6 +1177,7 @@ int hid_open_report(struct hid_device *device)
}
parser->device = device;
+ parser->active_collection = UINT_MAX;
end = start + size;
@@ -430,7 +430,7 @@ struct hid_local {
*/
struct hid_collection {
- struct hid_collection *parent;
+ unsigned int parent;
unsigned type;
unsigned usage;
unsigned level;
@@ -658,7 +658,7 @@ struct hid_parser {
unsigned int *collection_stack;
unsigned int collection_stack_ptr;
unsigned int collection_stack_size;
- struct hid_collection *active_collection;
+ unsigned int active_collection;
struct hid_device *device;
unsigned int scan_flags;
};
Storing HID collection parents as direct pointers while parsing HID report descriptors only works as long as the collection array is not reallocated, which happens for descriptors with a large number of collections. Then all stored pointers are invalidated in the middle of parsing, which results in invalid memory accesses. Instead of storing pointers, just store array indices, which stay valid across array reallocation. Store UINT_MAX for "no parent". Fixes: c53431eb696f ("HID: core: store the collections as a basic tree") Fixes: 5a4abb36f312 ("HID: core: process the Resolution Multiplier") Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com> --- drivers/hid/hid-core.c | 24 ++++++++++++++++-------- include/linux/hid.h | 4 ++-- 2 files changed, 18 insertions(+), 10 deletions(-)