aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2007-05-10 02:45:56 -0400
committerJiri Kosina <jkosina@suse.cz>2007-05-10 02:45:56 -0400
commitcdcb44e87bedcf5070eece61f89f9373a3810031 (patch)
treed9d1fdaa3b0e7789e0064377e3dedbd3ab6b9376 /drivers/hid
parentfe7ba31feadcc2cdb7749a8ed14960f989cbd021 (diff)
USB HID: hiddev - fix race between hiddev_send_event() and hiddev_release()
There is a small race window in which hiddev_release() could corrupt the list that is being processed for new event in hiddev_send_event(). Synchronize the operations over this list. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/usbhid/hiddev.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index a8b3d66cd498..488d61bdbf2c 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -51,6 +51,7 @@ struct hiddev {
51 wait_queue_head_t wait; 51 wait_queue_head_t wait;
52 struct hid_device *hid; 52 struct hid_device *hid;
53 struct list_head list; 53 struct list_head list;
54 spinlock_t list_lock;
54}; 55};
55 56
56struct hiddev_list { 57struct hiddev_list {
@@ -161,7 +162,9 @@ static void hiddev_send_event(struct hid_device *hid,
161{ 162{
162 struct hiddev *hiddev = hid->hiddev; 163 struct hiddev *hiddev = hid->hiddev;
163 struct hiddev_list *list; 164 struct hiddev_list *list;
165 unsigned long flags;
164 166
167 spin_lock_irqsave(&hiddev->list_lock, flags);
165 list_for_each_entry(list, &hiddev->list, node) { 168 list_for_each_entry(list, &hiddev->list, node) {
166 if (uref->field_index != HID_FIELD_INDEX_NONE || 169 if (uref->field_index != HID_FIELD_INDEX_NONE ||
167 (list->flags & HIDDEV_FLAG_REPORT) != 0) { 170 (list->flags & HIDDEV_FLAG_REPORT) != 0) {
@@ -171,6 +174,7 @@ static void hiddev_send_event(struct hid_device *hid,
171 kill_fasync(&list->fasync, SIGIO, POLL_IN); 174 kill_fasync(&list->fasync, SIGIO, POLL_IN);
172 } 175 }
173 } 176 }
177 spin_unlock_irqrestore(&hiddev->list_lock, flags);
174 178
175 wake_up_interruptible(&hiddev->wait); 179 wake_up_interruptible(&hiddev->wait);
176} 180}
@@ -235,9 +239,13 @@ static int hiddev_fasync(int fd, struct file *file, int on)
235static int hiddev_release(struct inode * inode, struct file * file) 239static int hiddev_release(struct inode * inode, struct file * file)
236{ 240{
237 struct hiddev_list *list = file->private_data; 241 struct hiddev_list *list = file->private_data;
242 unsigned long flags;
238 243
239 hiddev_fasync(-1, file, 0); 244 hiddev_fasync(-1, file, 0);
245
246 spin_lock_irqsave(&list->hiddev->list_lock, flags);
240 list_del(&list->node); 247 list_del(&list->node);
248 spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
241 249
242 if (!--list->hiddev->open) { 250 if (!--list->hiddev->open) {
243 if (list->hiddev->exist) 251 if (list->hiddev->exist)
@@ -257,6 +265,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
257static int hiddev_open(struct inode *inode, struct file *file) 265static int hiddev_open(struct inode *inode, struct file *file)
258{ 266{
259 struct hiddev_list *list; 267 struct hiddev_list *list;
268 unsigned long flags;
260 269
261 int i = iminor(inode) - HIDDEV_MINOR_BASE; 270 int i = iminor(inode) - HIDDEV_MINOR_BASE;
262 271
@@ -267,7 +276,11 @@ static int hiddev_open(struct inode *inode, struct file *file)
267 return -ENOMEM; 276 return -ENOMEM;
268 277
269 list->hiddev = hiddev_table[i]; 278 list->hiddev = hiddev_table[i];
279
280 spin_lock_irqsave(&list->hiddev->list_lock, flags);
270 list_add_tail(&list->node, &hiddev_table[i]->list); 281 list_add_tail(&list->node, &hiddev_table[i]->list);
282 spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
283
271 file->private_data = list; 284 file->private_data = list;
272 285
273 if (!list->hiddev->open++) 286 if (!list->hiddev->open++)
@@ -773,6 +786,7 @@ int hiddev_connect(struct hid_device *hid)
773 786
774 init_waitqueue_head(&hiddev->wait); 787 init_waitqueue_head(&hiddev->wait);
775 INIT_LIST_HEAD(&hiddev->list); 788 INIT_LIST_HEAD(&hiddev->list);
789 spin_lock_init(&hiddev->list_lock);
776 hiddev->hid = hid; 790 hiddev->hid = hid;
777 hiddev->exist = 1; 791 hiddev->exist = 1;
778 792