]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.6.2/hid-hidraw-don-t-deallocate-memory-when-it-is-in-use.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.6.2 / hid-hidraw-don-t-deallocate-memory-when-it-is-in-use.patch
CommitLineData
eea5abed
GKH
1From 4fe9f8e203fdad1524c04beb390f3c6099781ed9 Mon Sep 17 00:00:00 2001
2From: Ratan Nalumasu <ratan@google.com>
3Date: Sat, 22 Sep 2012 11:46:30 -0700
4Subject: HID: hidraw: don't deallocate memory when it is in use
5
6From: Ratan Nalumasu <ratan@google.com>
7
8commit 4fe9f8e203fdad1524c04beb390f3c6099781ed9 upstream.
9
10When a device is unplugged, wait for all processes that have opened the device
11to close before deallocating the device.
12
13Signed-off-by: Ratan Nalumasu <ratan@google.com>
14Signed-off-by: Jiri Kosina <jkosina@suse.cz>
15Cc: Kees Cook <keescook@chromium.org>
16Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
17
18---
19 drivers/hid/hidraw.c | 69 +++++++++++++++++++--------------------------------
20 1 file changed, 26 insertions(+), 43 deletions(-)
21
22--- a/drivers/hid/hidraw.c
23+++ b/drivers/hid/hidraw.c
24@@ -42,6 +42,7 @@ static struct cdev hidraw_cdev;
25 static struct class *hidraw_class;
26 static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
27 static DEFINE_MUTEX(minors_lock);
28+static void drop_ref(struct hidraw *hid, int exists_bit);
29
30 static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
31 {
32@@ -113,7 +114,7 @@ static ssize_t hidraw_send_report(struct
33 __u8 *buf;
34 int ret = 0;
35
36- if (!hidraw_table[minor]) {
37+ if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
38 ret = -ENODEV;
39 goto out;
40 }
41@@ -261,7 +262,7 @@ static int hidraw_open(struct inode *ino
42 }
43
44 mutex_lock(&minors_lock);
45- if (!hidraw_table[minor]) {
46+ if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
47 err = -ENODEV;
48 goto out_unlock;
49 }
50@@ -298,36 +299,12 @@ out:
51 static int hidraw_release(struct inode * inode, struct file * file)
52 {
53 unsigned int minor = iminor(inode);
54- struct hidraw *dev;
55 struct hidraw_list *list = file->private_data;
56- int ret;
57- int i;
58-
59- mutex_lock(&minors_lock);
60- if (!hidraw_table[minor]) {
61- ret = -ENODEV;
62- goto unlock;
63- }
64
65+ drop_ref(hidraw_table[minor], 0);
66 list_del(&list->node);
67- dev = hidraw_table[minor];
68- if (!--dev->open) {
69- if (list->hidraw->exist) {
70- hid_hw_power(dev->hid, PM_HINT_NORMAL);
71- hid_hw_close(dev->hid);
72- } else {
73- kfree(list->hidraw);
74- }
75- }
76-
77- for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
78- kfree(list->buffer[i].value);
79 kfree(list);
80- ret = 0;
81-unlock:
82- mutex_unlock(&minors_lock);
83-
84- return ret;
85+ return 0;
86 }
87
88 static long hidraw_ioctl(struct file *file, unsigned int cmd,
89@@ -529,21 +506,7 @@ EXPORT_SYMBOL_GPL(hidraw_connect);
90 void hidraw_disconnect(struct hid_device *hid)
91 {
92 struct hidraw *hidraw = hid->hidraw;
93-
94- mutex_lock(&minors_lock);
95- hidraw->exist = 0;
96-
97- device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
98-
99- hidraw_table[hidraw->minor] = NULL;
100-
101- if (hidraw->open) {
102- hid_hw_close(hid);
103- wake_up_interruptible(&hidraw->wait);
104- } else {
105- kfree(hidraw);
106- }
107- mutex_unlock(&minors_lock);
108+ drop_ref(hidraw, 1);
109 }
110 EXPORT_SYMBOL_GPL(hidraw_disconnect);
111
112@@ -585,3 +548,23 @@ void hidraw_exit(void)
113 unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
114
115 }
116+
117+static void drop_ref(struct hidraw *hidraw, int exists_bit)
118+{
119+ mutex_lock(&minors_lock);
120+ if (exists_bit) {
121+ hid_hw_close(hidraw->hid);
122+ hidraw->exist = 0;
123+ if (hidraw->open)
124+ wake_up_interruptible(&hidraw->wait);
125+ } else {
126+ --hidraw->open;
127+ }
128+
129+ if (!hidraw->open && !hidraw->exist) {
130+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
131+ hidraw_table[hidraw->minor] = NULL;
132+ kfree(hidraw);
133+ }
134+ mutex_unlock(&minors_lock);
135+}