Skip to content

Commit 57a38d9

Browse files
nalumasugregkh
authored andcommitted
HID: hidraw: don't deallocate memory when it is in use
commit 4fe9f8e upstream. When a device is unplugged, wait for all processes that have opened the device to close before deallocating the device. Signed-off-by: Ratan Nalumasu <ratan@google.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Cc: Kees Cook <keescook@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 117262a commit 57a38d9

File tree

1 file changed

+26
-43
lines changed

1 file changed

+26
-43
lines changed

drivers/hid/hidraw.c

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static struct cdev hidraw_cdev;
4242
static struct class *hidraw_class;
4343
static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
4444
static DEFINE_MUTEX(minors_lock);
45+
static void drop_ref(struct hidraw *hid, int exists_bit);
4546

4647
static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
4748
{
@@ -113,7 +114,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
113114
__u8 *buf;
114115
int ret = 0;
115116

116-
if (!hidraw_table[minor]) {
117+
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
117118
ret = -ENODEV;
118119
goto out;
119120
}
@@ -261,7 +262,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
261262
}
262263

263264
mutex_lock(&minors_lock);
264-
if (!hidraw_table[minor]) {
265+
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
265266
err = -ENODEV;
266267
goto out_unlock;
267268
}
@@ -298,36 +299,12 @@ static int hidraw_open(struct inode *inode, struct file *file)
298299
static int hidraw_release(struct inode * inode, struct file * file)
299300
{
300301
unsigned int minor = iminor(inode);
301-
struct hidraw *dev;
302302
struct hidraw_list *list = file->private_data;
303-
int ret;
304-
int i;
305-
306-
mutex_lock(&minors_lock);
307-
if (!hidraw_table[minor]) {
308-
ret = -ENODEV;
309-
goto unlock;
310-
}
311303

304+
drop_ref(hidraw_table[minor], 0);
312305
list_del(&list->node);
313-
dev = hidraw_table[minor];
314-
if (!--dev->open) {
315-
if (list->hidraw->exist) {
316-
hid_hw_power(dev->hid, PM_HINT_NORMAL);
317-
hid_hw_close(dev->hid);
318-
} else {
319-
kfree(list->hidraw);
320-
}
321-
}
322-
323-
for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
324-
kfree(list->buffer[i].value);
325306
kfree(list);
326-
ret = 0;
327-
unlock:
328-
mutex_unlock(&minors_lock);
329-
330-
return ret;
307+
return 0;
331308
}
332309

333310
static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -529,21 +506,7 @@ EXPORT_SYMBOL_GPL(hidraw_connect);
529506
void hidraw_disconnect(struct hid_device *hid)
530507
{
531508
struct hidraw *hidraw = hid->hidraw;
532-
533-
mutex_lock(&minors_lock);
534-
hidraw->exist = 0;
535-
536-
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
537-
538-
hidraw_table[hidraw->minor] = NULL;
539-
540-
if (hidraw->open) {
541-
hid_hw_close(hid);
542-
wake_up_interruptible(&hidraw->wait);
543-
} else {
544-
kfree(hidraw);
545-
}
546-
mutex_unlock(&minors_lock);
509+
drop_ref(hidraw, 1);
547510
}
548511
EXPORT_SYMBOL_GPL(hidraw_disconnect);
549512

@@ -585,3 +548,23 @@ void hidraw_exit(void)
585548
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
586549

587550
}
551+
552+
static void drop_ref(struct hidraw *hidraw, int exists_bit)
553+
{
554+
mutex_lock(&minors_lock);
555+
if (exists_bit) {
556+
hid_hw_close(hidraw->hid);
557+
hidraw->exist = 0;
558+
if (hidraw->open)
559+
wake_up_interruptible(&hidraw->wait);
560+
} else {
561+
--hidraw->open;
562+
}
563+
564+
if (!hidraw->open && !hidraw->exist) {
565+
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
566+
hidraw_table[hidraw->minor] = NULL;
567+
kfree(hidraw);
568+
}
569+
mutex_unlock(&minors_lock);
570+
}

0 commit comments

Comments
 (0)