diff options
author | Jiri Kosina <jkosina@suse.cz> | 2013-04-16 18:40:09 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-04-30 04:09:31 -0400 |
commit | 2353f2bea307390e015493118e425152b8a5a431 (patch) | |
tree | beb7fd2471690bbd8b0d0982c3b1f40f6784adba /drivers/hid | |
parent | a5f04b9df1113e0c16271afe5e43028f0d763f13 (diff) |
HID: protect hid_debug_list
Accesses to hid_device->hid_debug_list are not serialized properly, which
could result in SMP concurrency issues when HID debugfs events are accessesed
by multiple userspace processess.
Serialize all the list operations by a mutex.
Spotted by Al Viro.
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-core.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-debug.c | 6 |
2 files changed, 7 insertions, 0 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f86dd9708ca5..e7765ede339e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -2319,6 +2319,7 @@ struct hid_device *hid_allocate_device(void) | |||
2319 | 2319 | ||
2320 | init_waitqueue_head(&hdev->debug_wait); | 2320 | init_waitqueue_head(&hdev->debug_wait); |
2321 | INIT_LIST_HEAD(&hdev->debug_list); | 2321 | INIT_LIST_HEAD(&hdev->debug_list); |
2322 | mutex_init(&hdev->debug_list_lock); | ||
2322 | sema_init(&hdev->driver_lock, 1); | 2323 | sema_init(&hdev->driver_lock, 1); |
2323 | 2324 | ||
2324 | return hdev; | 2325 | return hdev; |
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 094cbcfe1e1a..7e56cb3855e3 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c | |||
@@ -580,12 +580,14 @@ void hid_debug_event(struct hid_device *hdev, char *buf) | |||
580 | int i; | 580 | int i; |
581 | struct hid_debug_list *list; | 581 | struct hid_debug_list *list; |
582 | 582 | ||
583 | mutex_lock(&hdev->debug_list_lock); | ||
583 | list_for_each_entry(list, &hdev->debug_list, node) { | 584 | list_for_each_entry(list, &hdev->debug_list, node) { |
584 | for (i = 0; i < strlen(buf); i++) | 585 | for (i = 0; i < strlen(buf); i++) |
585 | list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] = | 586 | list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] = |
586 | buf[i]; | 587 | buf[i]; |
587 | list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE; | 588 | list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE; |
588 | } | 589 | } |
590 | mutex_unlock(&hdev->debug_list_lock); | ||
589 | 591 | ||
590 | wake_up_interruptible(&hdev->debug_wait); | 592 | wake_up_interruptible(&hdev->debug_wait); |
591 | } | 593 | } |
@@ -990,7 +992,9 @@ static int hid_debug_events_open(struct inode *inode, struct file *file) | |||
990 | file->private_data = list; | 992 | file->private_data = list; |
991 | mutex_init(&list->read_mutex); | 993 | mutex_init(&list->read_mutex); |
992 | 994 | ||
995 | mutex_lock(&list->hdev->debug_list_lock); | ||
993 | list_add_tail(&list->node, &list->hdev->debug_list); | 996 | list_add_tail(&list->node, &list->hdev->debug_list); |
997 | mutex_unlock(&list->hdev->debug_list_lock); | ||
994 | 998 | ||
995 | out: | 999 | out: |
996 | return err; | 1000 | return err; |
@@ -1085,7 +1089,9 @@ static int hid_debug_events_release(struct inode *inode, struct file *file) | |||
1085 | { | 1089 | { |
1086 | struct hid_debug_list *list = file->private_data; | 1090 | struct hid_debug_list *list = file->private_data; |
1087 | 1091 | ||
1092 | mutex_lock(&list->hdev->debug_list_lock); | ||
1088 | list_del(&list->node); | 1093 | list_del(&list->node); |
1094 | mutex_unlock(&list->hdev->debug_list_lock); | ||
1089 | kfree(list->hid_debug_buf); | 1095 | kfree(list->hid_debug_buf); |
1090 | kfree(list); | 1096 | kfree(list); |
1091 | 1097 | ||