From: James Hogan Date: Tue, 20 Sep 2011 13:23:46 +0000 (+0200) Subject: HID: hidraw: protect hidraw_disconnect() better X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=65b01bd561dc995aab116aa784f97a37f7c49a65;p=linux-beck.git 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 Tested-by: David Herrmann Signed-off-by: Jiri Kosina --- diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index c79578b5a788..a8c2b7b6220a 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -510,13 +510,12 @@ void hidraw_disconnect(struct hid_device *hid) { struct hidraw *hidraw = hid->hidraw; + mutex_lock(&minors_lock); hidraw->exist = 0; device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); - mutex_lock(&minors_lock); hidraw_table[hidraw->minor] = NULL; - mutex_unlock(&minors_lock); if (hidraw->open) { hid_hw_close(hid); @@ -524,6 +523,7 @@ void hidraw_disconnect(struct hid_device *hid) } else { kfree(hidraw); } + mutex_unlock(&minors_lock); } EXPORT_SYMBOL_GPL(hidraw_disconnect);