aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2011-09-20 09:23:46 -0400
committerJiri Kosina <jkosina@suse.cz>2011-09-20 09:23:46 -0400
commit65b01bd561dc995aab116aa784f97a37f7c49a65 (patch)
treecebcfb510b789147e185eba651d383d61c071ca9
parente4e436e0bd480668834fe6849a52c5397b7be4fb (diff)
HID: hidraw: protect hidraw_disconnect() better
The function hidraw_disconnect() only acquires the hidraw minors_lock when clearing the entry in hidraw_table. However the device_destroy() call can cause a userland read/write to return with an error. It may cause the program to release the file descripter before the disconnect is finished. hidraw_disconnect() has already set hidraw->exist to 0, which makes hidraw_release() kfree the hidraw structure, which hidraw_disconnect() continues to access and even tries to kfree again. Similarly if a hidraw_release() occurs after setting hidraw->exist to 0, the same thing can happen. This is fixed by expanding the mutex critical section to cover the whole function from setting hidraw->exist to 0 to freeing the hidraw structure, preventing a hidraw_release() from interfering. Signed-off-by: James Hogan <james.hogan@imgtec.com> Tested-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hidraw.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index c79578b5a78..a8c2b7b6220 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -510,13 +510,12 @@ void hidraw_disconnect(struct hid_device *hid)
510{ 510{
511 struct hidraw *hidraw = hid->hidraw; 511 struct hidraw *hidraw = hid->hidraw;
512 512
513 mutex_lock(&minors_lock);
513 hidraw->exist = 0; 514 hidraw->exist = 0;
514 515
515 device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); 516 device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
516 517
517 mutex_lock(&minors_lock);
518 hidraw_table[hidraw->minor] = NULL; 518 hidraw_table[hidraw->minor] = NULL;
519 mutex_unlock(&minors_lock);
520 519
521 if (hidraw->open) { 520 if (hidraw->open) {
522 hid_hw_close(hid); 521 hid_hw_close(hid);
@@ -524,6 +523,7 @@ void hidraw_disconnect(struct hid_device *hid)
524 } else { 523 } else {
525 kfree(hidraw); 524 kfree(hidraw);
526 } 525 }
526 mutex_unlock(&minors_lock);
527} 527}
528EXPORT_SYMBOL_GPL(hidraw_disconnect); 528EXPORT_SYMBOL_GPL(hidraw_disconnect);
529 529